Add wdm update server support

-- add wdm update request processing and update response generation
mechanism
-- add TraitUpdatableDataSource
diff --git a/src/lib/core/WeaveDMConfig.h b/src/lib/core/WeaveDMConfig.h
index 742d7f4..66b1814 100644
--- a/src/lib/core/WeaveDMConfig.h
+++ b/src/lib/core/WeaveDMConfig.h
@@ -294,6 +294,18 @@
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
 
 /**
+ *  @def WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+ *
+ *  @brief
+ *    Enable (1) or disable (0) sending/handling update response
+ *    in Weave Data Management Next profile.
+ *
+ */
+#ifndef WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+#define WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT 1
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
+/**
  *  @def WDM_PUBLISHER_ENABLE_VIEW
  *
  *  @brief
@@ -573,6 +585,29 @@
 #endif /* WDM_MIN_UPDATE_SIZE */
 
 /**
+ * @def WDM_MAX_UPDATE_RESPONSE_SIZE
+ *
+ * @brief
+ *   Specify the maximum size (in bytes) of a WDM update response
+ *   payload. Note that the WDM update payload is also limited
+ *   by the size of `nl::Weave::System::PacketBuffer`
+ */
+#ifndef WDM_MAX_UPDATE_RESPONSE_SIZE
+#define WDM_MAX_UPDATE_RESPONSE_SIZE 2048
+#endif /* WDM_MAX_UPDATE_SIZE */
+
+/**
+ * @def WDM_MIN_UPDATE_RESPONSE_SIZE
+ *
+ * @brief
+ *   Specify the minimum size (in bytes) of a WDM update response
+ *   payload.
+ */
+#ifndef WDM_MIN_UPDATE_RESPONSE_SIZE
+#define WDM_MIN_UPDATE_RESPONSE_SIZE 1024
+#endif /* WDM_MIN_UPDATE_SIZE */
+
+/**
  *  @def TDM_DISABLE_STRICT_SCHEMA_COMPLIANCE
  *
  *  @brief
diff --git a/src/lib/profiles/common/WeaveMessage.cpp b/src/lib/profiles/common/WeaveMessage.cpp
index 00ddb8a..117669a 100644
--- a/src/lib/profiles/common/WeaveMessage.cpp
+++ b/src/lib/profiles/common/WeaveMessage.cpp
@@ -851,6 +851,7 @@
  * @brief Pack a ReferencedTLVData object using a TLVWriter.
  *
  * @param [in] i An iterator over the message being packed.
+ * @param [in] maxLen The maximum number of bytes that should be written to the output buffer.
  *
  * @return a WEAVE_ERROR - WEAVE_NO_ERROR if all goes well, otherwise
  * an error reflecting an inability of the writer to write the
@@ -858,7 +859,7 @@
  * return an error and so fails silently.
  */
 
-WEAVE_ERROR ReferencedTLVData::pack(MessageIterator &i)
+WEAVE_ERROR ReferencedTLVData::pack(MessageIterator &i, uint32_t maxLen)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     System::PacketBuffer *theBuffer = i.GetBuffer();
@@ -868,7 +869,7 @@
     if (theWriteCallback != NULL)
     {
         theData = i.thePoint;
-        writer.Init(theBuffer);
+        writer.Init(theBuffer, maxLen);
         theWriteCallback(writer, theAppState);
         theLength = theBuffer->DataLength() - oldDataLength;
         i.thePoint += theLength;
diff --git a/src/lib/profiles/common/WeaveMessage.h b/src/lib/profiles/common/WeaveMessage.h
index ca7d493..7589970 100644
--- a/src/lib/profiles/common/WeaveMessage.h
+++ b/src/lib/profiles/common/WeaveMessage.h
@@ -289,7 +289,7 @@
         return pack(i);
     };
 
-    WEAVE_ERROR pack(MessageIterator&i);
+    WEAVE_ERROR pack(MessageIterator&i, uint32_t maxLen = 0xFFFFFFFFUL);
 
     /**
      * Return the data length assuming that the object has been packed
diff --git a/src/lib/profiles/data-management/Current/SubscriptionEngine.cpp b/src/lib/profiles/data-management/Current/SubscriptionEngine.cpp
index b57d9a2..c0468a4 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionEngine.cpp
+++ b/src/lib/profiles/data-management/Current/SubscriptionEngine.cpp
@@ -32,11 +32,17 @@
 #include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
 #include <Weave/Profiles/data-management/DataManagement.h>
 #include <Weave/Profiles/data-management/NotificationEngine.h>
+#include <Weave/Profiles/status-report/StatusReportProfile.h>
 #include <Weave/Profiles/time/WeaveTime.h>
 #include <Weave/Support/crypto/WeaveCrypto.h>
 #include <Weave/Support/WeaveFaultInjection.h>
 #include <SystemLayer/SystemStats.h>
 
+#ifndef WEAVE_WDM_ALIGNED_TYPE
+#define WEAVE_WDM_ALIGNED_TYPE(address, type) \
+  reinterpret_cast<type *> WEAVE_SYSTEM_ALIGN_SIZE((size_t)(address), 4)
+#endif
+
 namespace nl {
 namespace Weave {
 namespace Profiles {
@@ -229,13 +235,12 @@
 WEAVE_ERROR SubscriptionEngine::NewClient(SubscriptionClient ** const appClient, Binding * const apBinding, void * const apAppState,
                                           SubscriptionClient::EventCallback const aEventCallback,
                                           const TraitCatalogBase<TraitDataSink> * const apCatalog,
-                                          const uint32_t aInactivityTimeoutDuringSubscribingMsec,
-                                          IWeaveWDMMutex * aUpdateMutex)
+                                          const uint32_t aInactivityTimeoutDuringSubscribingMsec, IWeaveWDMMutex * aUpdateMutex)
 {
     WEAVE_ERROR err = WEAVE_ERROR_NO_MEMORY;
 
 #if WEAVE_CONFIG_ENABLE_WDM_UPDATE
-    uint32_t maxSize        = WDM_MAX_UPDATE_SIZE;
+    uint32_t maxSize = WDM_MAX_UPDATE_SIZE;
 #else
     VerifyOrExit(aUpdateMutex == NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
 #endif // WEAVE_CONFIG_ENABLE_WDM_UPDATE
@@ -249,9 +254,9 @@
         if (SubscriptionClient::kState_Free == mClients[i].mCurrentState)
         {
             *appClient = &mClients[i];
-            err = (*appClient)->Init(apBinding, apAppState, aEventCallback, apCatalog,
-                                     aInactivityTimeoutDuringSubscribingMsec,
-                                     aUpdateMutex);
+            err =
+                (*appClient)
+                    ->Init(apBinding, apAppState, aEventCallback, apCatalog, aInactivityTimeoutDuringSubscribingMsec, aUpdateMutex);
 
             if (WEAVE_NO_ERROR != err)
             {
@@ -360,6 +365,17 @@
         func = OnSubscriptionlessNotification;
         break;
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
+
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    case kMsgType_UpdateRequest:
+        func = OnUpdateRequest;
+        break;
+
+    case kMsgType_PartialUpdateRequest:
+        WeaveLogDetail(DataManagement, "PartialUpdateRequest not supported yet for update server");
+        break;
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
     default:
         break;
     }
@@ -463,8 +479,7 @@
 }
 
 WEAVE_ERROR SubscriptionEngine::ProcessDataList(nl::Weave::TLV::TLVReader & aReader,
-                                                const TraitCatalogBase<TraitDataSink> * aCatalog,
-                                                bool & aOutIsPartialChange,
+                                                const TraitCatalogBase<TraitDataSink> * aCatalog, bool & aOutIsPartialChange,
                                                 TraitDataHandle & aOutTraitDataHandle,
                                                 IDataElementAccessControlDelegate & acDelegate)
 {
@@ -536,7 +551,7 @@
 #endif
         SuccessOrExit(err);
 
-        traitPath.mTraitDataHandle = handle;
+        traitPath.mTraitDataHandle    = handle;
         traitPath.mPropertyPathHandle = pathHandle;
 
         err = acDelegate.DataElementAccessCheck(traitPath, *aCatalog);
@@ -592,22 +607,20 @@
 
 exit:
     return err;
-
 }
 
 #if WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
-WEAVE_ERROR SubscriptionEngine::RegisterForSubscriptionlessNotifications(
-                     const TraitCatalogBase<TraitDataSink> * const apCatalog)
+WEAVE_ERROR SubscriptionEngine::RegisterForSubscriptionlessNotifications(const TraitCatalogBase<TraitDataSink> * const apCatalog)
 {
-    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    WEAVE_ERROR err                    = WEAVE_NO_ERROR;
     mSubscriptionlessNotifySinkCatalog = apCatalog;
 
     return err;
 }
 
 void SubscriptionEngine::OnSubscriptionlessNotification(nl::Weave::ExchangeContext * aEC, const nl::Inet::IPPacketInfo * aPktInfo,
-                                                        const nl::Weave::WeaveMessageInfo * aMsgInfo, uint32_t aProfileId, uint8_t aMsgType,
-                                                        PacketBuffer * aPayload)
+                                                        const nl::Weave::WeaveMessageInfo * aMsgInfo, uint32_t aProfileId,
+                                                        uint8_t aMsgType, PacketBuffer * aPayload)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     NotificationRequest::Parser notify;
@@ -624,8 +637,8 @@
     inParam.Clear();
     outParam.Clear();
 
-    inParam.mIncomingSubscriptionlessNotification.processingError = err;
-    inParam.mIncomingSubscriptionlessNotification.mMsgInfo = aMsgInfo;
+    inParam.mIncomingSubscriptionlessNotification.processingError            = err;
+    inParam.mIncomingSubscriptionlessNotification.mMsgInfo                   = aMsgInfo;
     outParam.mIncomingSubscriptionlessNotification.mShouldContinueProcessing = true;
 
     if (pEngine->mEventCallback)
@@ -679,8 +692,7 @@
         SubscriptionlessNotifyDataElementAccessControlDelegate acDelegate(aMsgInfo);
         IDataElementAccessControlDelegate & acDelegateRef = acDelegate;
 
-        err = ProcessDataList(reader, pEngine->mSubscriptionlessNotifySinkCatalog,
-                              isPartialChange, traitDataHandle, acDelegateRef);
+        err = ProcessDataList(reader, pEngine->mSubscriptionlessNotifySinkCatalog, isPartialChange, traitDataHandle, acDelegateRef);
         SuccessOrExit(err);
 
         if (isPartialChange)
@@ -711,16 +723,17 @@
         outParam.Clear();
 
         inParam.mIncomingSubscriptionlessNotification.processingError = err;
-        inParam.mIncomingSubscriptionlessNotification.mMsgInfo = aMsgInfo;
+        inParam.mIncomingSubscriptionlessNotification.mMsgInfo        = aMsgInfo;
         // Subscriptionless Notification completion event indication.
         pEngine->mEventCallback(pEngine->mAppState, kEvent_SubscriptionlessNotificationProcessingComplete, inParam, outParam);
     }
 }
 
-WEAVE_ERROR SubscriptionEngine::SubscriptionlessNotifyDataElementAccessControlDelegate::DataElementAccessCheck(const TraitPath & aTraitPath, const TraitCatalogBase<TraitDataSink> & aCatalog)
+WEAVE_ERROR SubscriptionEngine::SubscriptionlessNotifyDataElementAccessControlDelegate::DataElementAccessCheck(
+    const TraitPath & aTraitPath, const TraitCatalogBase<TraitDataSink> & aCatalog)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
-    TraitDataSink *dataSink;
+    TraitDataSink * dataSink;
     InEventParam inParam;
     OutEventParam outParam;
     SubscriptionEngine * pEngine = SubscriptionEngine::GetInstance();
@@ -734,22 +747,21 @@
     if (dataSink->AcceptsSubscriptionlessNotifications())
     {
         outParam.mDataElementAccessControlForNotification.mRejectNotification = false;
-        outParam.mDataElementAccessControlForNotification.mReason = WEAVE_NO_ERROR;
+        outParam.mDataElementAccessControlForNotification.mReason             = WEAVE_NO_ERROR;
     }
     else
     {
         outParam.mDataElementAccessControlForNotification.mRejectNotification = true;
-        outParam.mDataElementAccessControlForNotification.mReason = WEAVE_ERROR_ACCESS_DENIED;
+        outParam.mDataElementAccessControlForNotification.mReason             = WEAVE_ERROR_ACCESS_DENIED;
     }
 
-    inParam.mDataElementAccessControlForNotification.mPath = &aTraitPath;
+    inParam.mDataElementAccessControlForNotification.mPath    = &aTraitPath;
     inParam.mDataElementAccessControlForNotification.mCatalog = &aCatalog;
     inParam.mDataElementAccessControlForNotification.mMsgInfo = mMsgInfo;
 
     if (NULL != pEngine->mEventCallback)
     {
-        pEngine->mEventCallback(pEngine->mAppState, kEvent_DataElementAccessControlCheck,
-                                inParam, outParam);
+        pEngine->mEventCallback(pEngine->mAppState, kEvent_DataElementAccessControlCheck, inParam, outParam);
     }
 
     // If application rejects it then deny access, else set reason to whatever
@@ -765,7 +777,7 @@
 
 exit:
 
-   return err;
+    return err;
 }
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
 
@@ -1454,7 +1466,7 @@
                 statusReportCode = nl::Weave::Profiles::DataManagement::kStatus_NotTimeSyncedYet;
                 ExitNow();
             }
-            else if (now_usec >= (uint64_t)command->expiryTimeMicroSecond)
+            else if (now_usec >= (uint64_t) command->expiryTimeMicroSecond)
             {
                 statusReportCode = nl::Weave::Profiles::DataManagement::kStatus_RequestExpiredInTime;
                 ExitNow();
@@ -1476,15 +1488,13 @@
                 ExitNow();
             }
         }
-
         // Note we cannot just use pathReader at here because the TDM related functions
         // generally assume they can move the reader at their will.
         // Note that callee is supposed to cache whatever is useful in the TLV stream into its own memory
         // when this callback returns, we'd destroy the TLV object
 
-        dataSource->OnCustomCommand(command, aMsgInfo, aPayload, command->commandType,
-                                    command->IsExpiryTimeValid(), command->expiryTimeMicroSecond,
-                                    command->IsMustBeVersionValid(), command->mustBeVersion,
+        dataSource->OnCustomCommand(command, aMsgInfo, aPayload, command->commandType, command->IsExpiryTimeValid(),
+                                    command->expiryTimeMicroSecond, command->IsMustBeVersionValid(), command->mustBeVersion,
                                     reader);
 
         command  = NULL;
@@ -1515,7 +1525,671 @@
 }
 #endif // WDM_PUBLISHER_ENABLE_CUSTOM_COMMANDS
 
-#endif // #if WDM_ENABLE_SUBSCRIPTION_PUBLISHER
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+WEAVE_ERROR SubscriptionEngine::AllocateRightSizedBuffer(PacketBuffer *& buf, const uint32_t desiredSize, const uint32_t minSize,
+                                                         uint32_t & outMaxPayloadSize)
+{
+    WEAVE_ERROR err          = WEAVE_NO_ERROR;
+    uint32_t bufferAllocSize = 0;
+    uint32_t maxWeavePayloadSize;
+    uint32_t weaveTrailerSize = WEAVE_TRAILER_RESERVE_SIZE;
+    uint32_t weaveHeaderSize  = WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE;
+
+    bufferAllocSize = nl::Weave::min(
+        desiredSize, static_cast<uint32_t>(WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX - weaveHeaderSize - weaveTrailerSize));
+
+    // Add the Weave Trailer size as NewWithAvailableSize() includes that in
+    // availableSize.
+    bufferAllocSize += weaveTrailerSize;
+
+    buf = PacketBuffer::NewWithAvailableSize(weaveHeaderSize, bufferAllocSize);
+    VerifyOrExit(buf != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+    maxWeavePayloadSize = WeaveMessageLayer::GetMaxWeavePayloadSize(buf, true, WEAVE_CONFIG_DEFAULT_UDP_MTU_SIZE);
+
+    outMaxPayloadSize = nl::Weave::min(maxWeavePayloadSize, bufferAllocSize);
+
+    if (outMaxPayloadSize < minSize)
+    {
+        err = WEAVE_ERROR_BUFFER_TOO_SMALL;
+
+        PacketBuffer::Free(buf);
+        buf = NULL;
+    }
+
+exit:
+    return err;
+}
+
+void SubscriptionEngine::ConstructStatusListVersionList(nl::Weave::TLV::TLVWriter & aWriter, void * apContext)
+{
+    WEAVE_ERROR err                                 = WEAVE_NO_ERROR;
+    nl::Weave::TLV::TLVWriter checkpoint            = aWriter;
+    TraitDataSource * dataSource                    = NULL;
+    struct StatusDataHandleElement * elementTracker = NULL;
+    UpdateResponseWriterContext * context           = NULL;
+    UpdateResponse::Builder updateResponseBuilder;
+
+    VerifyOrExit(NULL != apContext, err = WEAVE_ERROR_INCORRECT_STATE);
+    context = static_cast<UpdateResponseWriterContext *>(apContext);
+
+    err = updateResponseBuilder.Init(&aWriter);
+    SuccessOrExit(err);
+
+    elementTracker = static_cast<struct StatusDataHandleElement *>(context->mpFirstStatusDataHandleElement);
+    {
+        VersionList::Builder & lVLBuilder = updateResponseBuilder.CreateVersionListBuilder();
+        for (uint32_t i = 0; i < context->mNumDataElements; i++)
+        {
+            if ((elementTracker->mProfileId == Weave::Profiles::kWeaveProfile_Common) &&
+                (elementTracker->mStatusCode == Weave::Profiles::Common::kStatus_AccessDenied))
+            {
+                lVLBuilder.AddNull();
+            }
+            else if ((elementTracker->mProfileId == Weave::Profiles::kWeaveProfile_WDM) &&
+                     (elementTracker->mStatusCode == kStatus_InvalidPath))
+            {
+                lVLBuilder.AddNull();
+            }
+            else if (context->mpCatalog->Locate(elementTracker->mTraitDataHandle, &dataSource) == WEAVE_NO_ERROR)
+            {
+                lVLBuilder.AddVersion(dataSource->GetVersion());
+            }
+            else
+            {
+                lVLBuilder.AddNull();
+            }
+            elementTracker++;
+        }
+        lVLBuilder.EndOfVersionList();
+        SuccessOrExit(lVLBuilder.GetError());
+    }
+
+    elementTracker = static_cast<struct StatusDataHandleElement *>(context->mpFirstStatusDataHandleElement);
+    {
+        StatusList::Builder & lSLBuilder = updateResponseBuilder.CreateStatusListBuilder();
+        for (uint32_t j = 0; j < context->mNumDataElements; j++)
+        {
+            lSLBuilder.AddStatus(elementTracker->mProfileId, elementTracker->mStatusCode);
+            elementTracker++;
+        }
+        lSLBuilder.EndOfStatusList();
+        SuccessOrExit(lSLBuilder.GetError());
+    }
+
+    updateResponseBuilder.EndOfResponse();
+    SuccessOrExit(updateResponseBuilder.GetError());
+
+    aWriter.Finalize();
+
+    WeaveLogDetail(DataManagement, "ConstructStatusListVersionList success with number of elements %d", context->mNumDataElements);
+
+exit:
+    if (err != WEAVE_NO_ERROR)
+    {
+        aWriter = checkpoint;
+    }
+}
+
+void SubscriptionEngine::BuildStatusDataHandleElement(PacketBuffer * pBuf, TraitDataHandle aTraitDataHandle, WEAVE_ERROR & err,
+                                                      uint32_t aCurrentIndex)
+{
+    uint32_t profileId  = 0;
+    uint16_t statusCode = 0;
+
+    if (WEAVE_ERROR_ACCESS_DENIED == err)
+    {
+        profileId  = Weave::Profiles::kWeaveProfile_Common;
+        statusCode = Weave::Profiles::Common::kStatus_AccessDenied;
+        err        = WEAVE_NO_ERROR;
+    }
+    else if (WEAVE_ERROR_INVALID_PROFILE_ID == err)
+    {
+        profileId  = Weave::Profiles::kWeaveProfile_WDM;
+        statusCode = kStatus_InvalidPath;
+        err        = WEAVE_NO_ERROR;
+    }
+    else if (WEAVE_ERROR_WDM_VERSION_MISMATCH == err)
+    {
+        profileId  = Weave::Profiles::kWeaveProfile_WDM;
+        statusCode = kStatus_VersionMismatch;
+        err        = WEAVE_NO_ERROR;
+    }
+    else if (WEAVE_NO_ERROR == err)
+    {
+        profileId  = Weave::Profiles::kWeaveProfile_Common;
+        statusCode = Weave::Profiles::Common::kStatus_Success;
+    }
+    else
+    {
+        profileId  = Weave::Profiles::kWeaveProfile_Common;
+        statusCode = Weave::Profiles::Common::kStatus_InternalError;
+        WeaveLogError(DataManagement, "fail to process UpdateRequest with error %s at %s:%d", nl::ErrorStr(err), __FILE__, __LINE__);
+    }
+
+    StatusDataHandleElement * statusDataHandleList = WEAVE_WDM_ALIGNED_TYPE(pBuf->Start(), StatusDataHandleElement);
+    statusDataHandleList[aCurrentIndex].mProfileId       = profileId;
+    statusDataHandleList[aCurrentIndex].mStatusCode      = statusCode;
+    statusDataHandleList[aCurrentIndex].mTraitDataHandle = aTraitDataHandle;
+}
+
+/**
+ * Check if this triat path is the starting one
+ */
+bool SubscriptionEngine::IsStartingPath(StatusDataHandleElement * apStatusDataHandleList, TraitDataHandle aTraitDataHandle,
+                                        uint32_t aCurrentIndex)
+{
+    bool isStarting = true;
+    // TODO: Optimize to reduce lookup loop
+    for (uint32_t index = 0; index < aCurrentIndex; index++)
+    {
+        if ((nl::Weave::Profiles::kWeaveProfile_Common == apStatusDataHandleList[index].mProfileId) &&
+            (nl::Weave::Profiles::Common::kStatus_Success == apStatusDataHandleList[index].mStatusCode) &&
+            (aTraitDataHandle == apStatusDataHandleList[index].mTraitDataHandle))
+        {
+            isStarting = false;
+        }
+    }
+    return isStarting;
+}
+
+/**
+ * Update version for all traits according to temporary statusDataHandleList, and bump version once at starting path
+ * for each trait
+ */
+WEAVE_ERROR SubscriptionEngine::UpdateTraitVersions(PacketBuffer * apBuf, const TraitCatalogBase<TraitDataSource> * apCatalog,
+                                                    uint32_t aNumDataElements)
+{
+    WEAVE_ERROR err                            = WEAVE_NO_ERROR;
+    TraitDataSource * dataSource               = NULL;
+    TraitUpdatableDataSource * updatableSource = NULL;
+    StatusDataHandleElement * statusDataHandleList = WEAVE_WDM_ALIGNED_TYPE(apBuf->Start(), StatusDataHandleElement);
+
+    for (uint32_t index = 0; index < aNumDataElements; index++)
+    {
+        if ((nl::Weave::Profiles::kWeaveProfile_Common == statusDataHandleList[index].mProfileId) &&
+            (nl::Weave::Profiles::Common::kStatus_Success == statusDataHandleList[index].mStatusCode))
+        {
+
+            err = apCatalog->Locate(statusDataHandleList[index].mTraitDataHandle, &dataSource);
+            SuccessOrExit(err);
+
+            updatableSource = static_cast<TraitUpdatableDataSource *>(dataSource);
+
+            if (IsStartingPath(statusDataHandleList, statusDataHandleList[index].mTraitDataHandle, index))
+            {
+                updatableSource->IncrementVersion();
+                WeaveLogDetail(DataManagement, "<UpdateTraitVersions> [Trait %08x] bumped version: 0x%" PRIx64 " ",
+                               updatableSource->GetSchemaEngine()->GetProfileId(), updatableSource->GetVersion());
+            }
+            else
+            {
+                WeaveLogDetail(DataManagement, "<UpdateTraitVersions> [Trait %08x] version: 0x%" PRIx64 " (no-change)",
+                               updatableSource->GetSchemaEngine()->GetProfileId(), updatableSource->GetVersion());
+            }
+        }
+    }
+
+exit:
+    return err;
+}
+
+/**
+ * If update request is malformed, it would send status report along with error status.
+ */
+WEAVE_ERROR SubscriptionEngine::SendFaultyUpdateResponse(Weave::ExchangeContext * apEC)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    uint8_t * p;
+    uint8_t statusReportLen = 6;
+    PacketBuffer * msgBuf   = PacketBuffer::NewWithAvailableSize(statusReportLen);
+    VerifyOrExit(NULL != msgBuf, err = WEAVE_ERROR_NO_MEMORY);
+
+    p = msgBuf->Start();
+    nl::Weave::Encoding::LittleEndian::Write32(p, Weave::Profiles::kWeaveProfile_Common);
+    nl::Weave::Encoding::LittleEndian::Write16(p, Weave::Profiles::Common::kStatus_InternalError);
+    msgBuf->SetDataLength(statusReportLen);
+
+    err    = apEC->SendMessage(Profiles::kWeaveProfile_Common, Profiles::Common::kMsgType_StatusReport, msgBuf);
+    msgBuf = NULL;
+    SuccessOrExit(err);
+
+exit:
+    if (msgBuf != NULL)
+    {
+        PacketBuffer::Free(msgBuf);
+        msgBuf = NULL;
+    }
+    return err;
+}
+
+/**
+ * Relocating statusDataHandleList to the end of Update Response buffer, based upon existFailure and
+ * statusDataHandleList, it constructs and sends status report.
+ */
+WEAVE_ERROR SubscriptionEngine::SendUpdateResponse(Weave::ExchangeContext * apEC, uint32_t aNumDataElements,
+                                                   const TraitCatalogBase<TraitDataSource> * apCatalog, PacketBuffer * apBuf,
+                                                   bool existFailure, uint32_t aMaxPayloadSize)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    UpdateResponseWriterContext context;
+    StatusReport statusReport;
+    ReferencedTLVData referenceTLVData;
+    uint32_t totalStatusDataHandleListBytes = 0;
+    uint32_t overalStatusProfile            = Weave::Profiles::kWeaveProfile_Common;
+    uint16_t overalStatusCode               = Weave::Profiles::Common::kStatus_Success;
+    uint8_t * movedStartAddr                = NULL;
+    uint8_t * pBufStartAddr                 = WEAVE_WDM_ALIGNED_TYPE(apBuf->Start(), uint8_t);
+
+    totalStatusDataHandleListBytes = aNumDataElements * sizeof(StatusDataHandleElement);
+
+    WeaveLogDetail(DataManagement, "relocating the %d bytes statusDataHandleList to the end, NumDataElements is %d",
+                   totalStatusDataHandleListBytes, aNumDataElements);
+
+    movedStartAddr = WEAVE_WDM_ALIGNED_TYPE(pBufStartAddr + aMaxPayloadSize - totalStatusDataHandleListBytes - 3, uint8_t);
+
+    memmove(movedStartAddr, pBufStartAddr, totalStatusDataHandleListBytes);
+
+    context.mpFirstStatusDataHandleElement = movedStartAddr;
+    context.mpCatalog                      = apCatalog;
+    context.mNumDataElements               = aNumDataElements;
+
+    // TODO: Refactor StatusReport and remove referenceTLVData
+    err = referenceTLVData.init(ConstructStatusListVersionList, &context);
+    SuccessOrExit(err);
+
+    if (existFailure)
+    {
+        overalStatusProfile = Weave::Profiles::kWeaveProfile_WDM;
+        overalStatusCode    = kStatus_MultipleFailures;
+    }
+    else
+    {
+        overalStatusProfile = Weave::Profiles::kWeaveProfile_Common;
+        overalStatusCode    = Weave::Profiles::Common::kStatus_Success;
+    }
+
+    err = statusReport.init(overalStatusProfile, overalStatusCode, &referenceTLVData);
+    SuccessOrExit(err);
+
+    err = statusReport.pack(apBuf, aMaxPayloadSize - totalStatusDataHandleListBytes);
+    SuccessOrExit(err);
+
+    WeaveLogDetail(DataManagement, "Send Update Response with profileId 0x%" PRIX32 " statusCode 0x%" PRIX16 " ",
+                   overalStatusProfile, overalStatusCode);
+    err   = apEC->SendMessage(Weave::Profiles::kWeaveProfile_Common, Weave::Profiles::Common::kMsgType_StatusReport, apBuf);
+    apBuf = NULL;
+
+exit:
+    if (apBuf != NULL)
+    {
+        PacketBuffer::Free(apBuf);
+        apBuf = NULL;
+    }
+    return err;
+}
+
+/**
+ * Run access check to check if DE is allowed, then during conditional DE loop, if DE does not have required version,
+ * skip this one, otherwises its required version for current DE should be same as current trait.
+ * During unconditional loop, if its required version is not 0, skip this one.
+ * Finally it starts to store data element
+ */
+WEAVE_ERROR SubscriptionEngine::ProcessUpdateRequestDataElement(Weave::TLV::TLVReader & aReader, TraitDataHandle & aHandle,
+                                                                PropertyPathHandle & aPathHandle,
+                                                                const TraitCatalogBase<TraitDataSource> * apCatalog,
+                                                                IUpdateRequestDataElementAccessControlDelegate & acDelegate,
+                                                                bool aConditionalLoop, uint32_t aCurrentIndex, bool & aExistFailure,
+                                                                PacketBuffer * apBuf)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    Weave::TLV::TLVReader pathReader;
+    Weave::TLV::TLVReader dataReader;
+    TraitPath traitPath;
+    DataElement::Parser element;
+    uint64_t requiredVersion = 0;
+    uint64_t versionInTrait  = 0;
+    bool isPartialChange     = false;
+    bool isLocked            = false;
+    bool needSkip            = false;
+    bool isConditionalDE     = true;
+    SchemaVersionRange versionRange;
+    TraitDataSource * dataSource               = NULL;
+    TraitUpdatableDataSource * updatableSource = NULL;
+
+    dataReader.Init(aReader);
+
+    err = element.Init(aReader);
+    SuccessOrExit(err);
+    err = element.GetReaderOnPath(&pathReader);
+    SuccessOrExit(err);
+
+    // Not support partial change handling
+    isPartialChange = false;
+    element.GetPartialChangeFlag(&isPartialChange);
+    VerifyOrExit(isPartialChange == false, err = WEAVE_ERROR_INCORRECT_STATE);
+
+    err = apCatalog->AddressToHandle(pathReader, aHandle, versionRange);
+    SuccessOrExit(err);
+
+    err = apCatalog->Locate(aHandle, &dataSource);
+    SuccessOrExit(err);
+    err = dataSource->GetSchemaEngine()->MapPathToHandle(pathReader, aPathHandle);
+#if TDM_DISABLE_STRICT_SCHEMA_COMPLIANCE
+    if (err == WEAVE_ERROR_TLV_TAG_NOT_FOUND)
+    {
+        WeaveLogDetail(DataManagement, "Ignoring un-mappable path!");
+        err = WEAVE_NO_ERROR;
+    }
+#endif
+
+    traitPath.mTraitDataHandle    = aHandle;
+    traitPath.mPropertyPathHandle = aPathHandle;
+
+    err = acDelegate.DataElementAccessCheck(traitPath, *apCatalog);
+    SuccessOrExit(err);
+
+    updatableSource = static_cast<TraitUpdatableDataSource *>(dataSource);
+    updatableSource->Lock();
+    isLocked = true;
+
+    versionInTrait = updatableSource->GetVersion();
+
+    err = element.GetVersion(&requiredVersion);
+    if (WEAVE_END_OF_TLV == err)
+    {
+        err             = WEAVE_NO_ERROR;
+        isConditionalDE = false;
+    }
+    SuccessOrExit(err);
+
+    if (aConditionalLoop)
+    {
+        VerifyOrExit(isConditionalDE, needSkip = true);
+        VerifyOrExit(versionInTrait == requiredVersion, err = WEAVE_ERROR_WDM_VERSION_MISMATCH);
+    }
+    else
+    {
+        VerifyOrExit(!isConditionalDE, needSkip = true);
+    }
+    WeaveLogDetail(DataManagement, "processing %s DE, index %d", aConditionalLoop ? "conditional" : "unconditional", aCurrentIndex);
+
+    err = updatableSource->StoreDataElement(aPathHandle, dataReader, 0, NULL, NULL);
+    SuccessOrExit(err);
+
+    updatableSource->SetDirty(aPathHandle);
+
+    updatableSource->Unlock(true);
+    isLocked = false;
+
+exit:
+    if (isLocked && updatableSource != NULL)
+    {
+        updatableSource->Unlock(true);
+    }
+
+    if (WEAVE_NO_ERROR != err)
+    {
+        WeaveLogDetail(DataManagement, "There exists %d DE with err %d", aCurrentIndex, err);
+        aExistFailure = true;
+    }
+
+    if (!needSkip)
+    {
+        BuildStatusDataHandleElement(apBuf, aHandle, err, aCurrentIndex);
+    }
+
+    return err;
+}
+
+/**
+ * Loop through all data elements in list and process either conditional data elements or unconditional data elements in
+ * one loop, and build temporary statusDataHandleList. Later it would use this list to construct update response.
+ */
+WEAVE_ERROR SubscriptionEngine::ProcessUpdateRequestDataList(Weave::TLV::TLVReader & aReader, PacketBuffer * apBuf,
+                                                             const TraitCatalogBase<TraitDataSource> * apCatalog,
+                                                             IUpdateRequestDataElementAccessControlDelegate & acDelegate,
+                                                             bool & aExistFailure, uint32_t & aNumDataElements,
+                                                             bool aConditionalLoop)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    Weave::TLV::TLVReader dataReader;
+    dataReader.Init(aReader);
+
+    for (aNumDataElements = 0; WEAVE_NO_ERROR == (err = dataReader.Next()); aNumDataElements++)
+    {
+        TraitDataHandle handle;
+        PropertyPathHandle pathHandle;
+
+        // if it is running conditional loop, needs to skip unconditional elements, vice versa.
+        err = ProcessUpdateRequestDataElement(dataReader, handle, pathHandle, apCatalog, acDelegate, aConditionalLoop,
+                                              aNumDataElements, aExistFailure, apBuf);
+        SuccessOrExit(err);
+    }
+
+    // if we have exhausted this container
+    if (WEAVE_END_OF_TLV == err)
+    {
+        err = WEAVE_NO_ERROR;
+    }
+
+exit:
+    return err;
+}
+
+/**
+ * Apply all conditional DEs first, then apply all unconditional DEs second, during loop, add status and dataHandle to
+ * temporary result list. Then update starting version for traits and generate update response.
+ */
+WEAVE_ERROR SubscriptionEngine::ProcessUpdateRequest(Weave::ExchangeContext * apEC, Weave::TLV::TLVReader & aReader,
+                                                     const TraitCatalogBase<TraitDataSource> * apCatalog,
+                                                     IUpdateRequestDataElementAccessControlDelegate & acDelegate)
+{
+    WEAVE_ERROR err          = WEAVE_NO_ERROR;
+    PacketBuffer * pBuf      = NULL;
+    bool existFailure        = false;
+    uint32_t numDataElements = 0;
+    uint32_t maxPayloadSize  = 0;
+
+    VerifyOrExit(apCatalog != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+    err = AllocateRightSizedBuffer(pBuf, WDM_MAX_UPDATE_RESPONSE_SIZE, WDM_MIN_UPDATE_RESPONSE_SIZE, maxPayloadSize);
+    SuccessOrExit(err);
+
+    // process conditional DEs
+    err = ProcessUpdateRequestDataList(aReader, pBuf, apCatalog, acDelegate, existFailure, numDataElements, true);
+    SuccessOrExit(err);
+
+    // process unconditional DEs
+    err = ProcessUpdateRequestDataList(aReader, pBuf, apCatalog, acDelegate, existFailure, numDataElements, false);
+    SuccessOrExit(err);
+
+    // update trait versions
+    err = UpdateTraitVersions(pBuf, apCatalog, numDataElements);
+    SuccessOrExit(err);
+
+    err  = SendUpdateResponse(apEC, numDataElements, apCatalog, pBuf, existFailure, maxPayloadSize);
+    pBuf = NULL;
+
+exit:
+
+    if (pBuf != NULL)
+    {
+        PacketBuffer::Free(pBuf);
+    }
+
+    if (WEAVE_NO_ERROR != err)
+    {
+        SendFaultyUpdateResponse(apEC);
+    }
+    return err;
+}
+
+/**
+ * Process UpdateRequest if Data list is present and send notification if subscription exists
+ */
+void SubscriptionEngine::OnUpdateRequest(Weave::ExchangeContext * apEC, const Inet::IPPacketInfo * aPktInfo,
+                                         const Weave::WeaveMessageInfo * aMsgInfo, uint32_t aProfileId, uint8_t aMsgType,
+                                         PacketBuffer * aPayload)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    UpdateRequest::Parser update;
+    Weave::TLV::TLVReader reader;
+    bool isDataListPresent     = false;
+    bool hasUpdateRequestBegin = false;
+    InEventParam inParam;
+    OutEventParam outParam;
+
+    SubscriptionEngine * const pEngine = reinterpret_cast<SubscriptionEngine *>(apEC->AppState);
+
+    inParam.Clear();
+    outParam.Clear();
+
+    inParam.mIncomingUpdateRequest.processingError            = err;
+    inParam.mIncomingUpdateRequest.mMsgInfo                   = aMsgInfo;
+    outParam.mIncomingUpdateRequest.mShouldContinueProcessing = true;
+
+    if (pEngine->mEventCallback)
+    {
+        pEngine->mEventCallback(pEngine->mAppState, kEvent_OnIncomingUpdateRequest, inParam, outParam);
+    }
+
+    if (!outParam.mIncomingUpdateRequest.mShouldContinueProcessing)
+    {
+        WeaveLogDetail(DataManagement, "Update not allowed");
+        ExitNow();
+    }
+
+    pEngine->mPublisherCatalog->DispatchEvent(TraitUpdatableDataSource::kEventUpdateRequestBegin, NULL);
+    hasUpdateRequestBegin = true;
+
+    reader.Init(aPayload);
+
+    err = reader.Next();
+    SuccessOrExit(err);
+
+    err = update.Init(reader);
+    SuccessOrExit(err);
+
+#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
+    err = update.CheckSchemaValidity();
+    SuccessOrExit(err);
+#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
+
+    {
+        DataList::Parser dataList;
+
+        err = update.GetDataList(&dataList);
+        if (WEAVE_NO_ERROR == err)
+        {
+            isDataListPresent = true;
+        }
+        else if (WEAVE_END_OF_TLV == err)
+        {
+            isDataListPresent = false;
+            err               = WEAVE_NO_ERROR;
+        }
+        SuccessOrExit(err);
+
+        // re-initialize the reader to point to individual date element (reuse to save stack depth).
+        dataList.GetReader(&reader);
+    }
+
+    if (isDataListPresent)
+    {
+        UpdateRequestDataElementAccessControlDelegate acDelegate(aMsgInfo);
+        IUpdateRequestDataElementAccessControlDelegate & acDelegateRef = acDelegate;
+
+        err = ProcessUpdateRequest(apEC, reader, pEngine->mPublisherCatalog, acDelegateRef);
+        SuccessOrExit(err);
+
+        pEngine->GetNotificationEngine()->ScheduleRun();
+    }
+
+exit:
+    if (hasUpdateRequestBegin)
+    {
+        pEngine->mPublisherCatalog->DispatchEvent(TraitUpdatableDataSource::kEventUpdateRequestEnd, NULL);
+    }
+
+    if (NULL != aPayload)
+    {
+        PacketBuffer::Free(aPayload);
+        aPayload = NULL;
+    }
+
+    if (NULL != apEC)
+    {
+        apEC->Abort();
+        apEC = NULL;
+    }
+
+    if (NULL != pEngine->mEventCallback)
+    {
+        inParam.Clear();
+        outParam.Clear();
+
+        inParam.mIncomingUpdateRequest.processingError = err;
+        inParam.mIncomingUpdateRequest.mMsgInfo        = aMsgInfo;
+        // Update completion event indication.
+        pEngine->mEventCallback(pEngine->mAppState, kEvent_UpdateRequestProcessingComplete, inParam, outParam);
+    }
+}
+
+WEAVE_ERROR SubscriptionEngine::UpdateRequestDataElementAccessControlDelegate::DataElementAccessCheck(
+    const TraitPath & aTraitPath, const TraitCatalogBase<TraitDataSource> & aCatalog)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    TraitDataSource * dataSource;
+    InEventParam inParam;
+    OutEventParam outParam;
+    SubscriptionEngine * pEngine = SubscriptionEngine::GetInstance();
+
+    err = aCatalog.Locate(aTraitPath.mTraitDataHandle, &dataSource);
+    SuccessOrExit(err);
+
+    inParam.Clear();
+    outParam.Clear();
+
+    if (dataSource->IsUpdatableDataSource())
+    {
+        outParam.mDataElementAccessControlForUpdateRequest.mRejectUpdateRequest = false;
+        outParam.mDataElementAccessControlForUpdateRequest.mReason              = WEAVE_NO_ERROR;
+    }
+    else
+    {
+        outParam.mDataElementAccessControlForUpdateRequest.mRejectUpdateRequest = true;
+        outParam.mDataElementAccessControlForUpdateRequest.mReason              = WEAVE_ERROR_ACCESS_DENIED;
+    }
+
+    inParam.mDataElementAccessControlForUpdateRequest.mPath    = &aTraitPath;
+    inParam.mDataElementAccessControlForUpdateRequest.mCatalog = &aCatalog;
+    inParam.mDataElementAccessControlForUpdateRequest.mMsgInfo = mMsgInfo;
+
+    if (NULL != pEngine->mEventCallback)
+    {
+        pEngine->mEventCallback(pEngine->mAppState, kEvent_UpdateRequestDataElementAccessControlCheck, inParam, outParam);
+    }
+
+    // If application rejects it then deny access, else set reason to whatever
+    // reason is set by application.
+    if (outParam.mDataElementAccessControlForUpdateRequest.mRejectUpdateRequest == true)
+    {
+        err = WEAVE_ERROR_ACCESS_DENIED;
+    }
+    else
+    {
+        err = outParam.mDataElementAccessControlForUpdateRequest.mReason;
+    }
+
+exit:
+
+    return err;
+}
+
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
+#endif // WDM_ENABLE_SUBSCRIPTION_PUBLISHER
 
 }; // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
 }; // namespace Profiles
diff --git a/src/lib/profiles/data-management/Current/SubscriptionEngine.h b/src/lib/profiles/data-management/Current/SubscriptionEngine.h
index 51bd71e..941c7a8 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionEngine.h
+++ b/src/lib/profiles/data-management/Current/SubscriptionEngine.h
@@ -53,6 +53,15 @@
     virtual WEAVE_ERROR Unlock(void) = 0;
 };
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+class IUpdateRequestDataElementAccessControlDelegate
+{
+public:
+    virtual WEAVE_ERROR DataElementAccessCheck(const TraitPath & aTraitPath,
+                                               const TraitCatalogBase<TraitDataSource> & aCatalog) = 0;
+};
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 /**
  * @class SubscriptionEngine
  *
@@ -84,11 +93,17 @@
 #if WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
         kEvent_OnIncomingSubscriptionlessNotification =
             1, ///< Called when an incoming subscriptionless notification has arrived before updating the data element.
-        kEvent_DataElementAccessControlCheck =
-            2, ///< Called when an incoming subscriptionless notification is being processed for access control of each data element.
+        kEvent_DataElementAccessControlCheck = 2, ///< Called when an incoming subscriptionless notification is being processed for
+                                                  ///< access control of each data element.
         kEvent_SubscriptionlessNotificationProcessingComplete =
             3, ///< Called upon completion of processing of all trait data in the subscriptionless notify.
 #endif         // #if WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+        kEvent_OnIncomingUpdateRequest = 4, ///< Called when an incoming update has arrived before updating the data element.
+        kEvent_UpdateRequestDataElementAccessControlCheck =
+            5, ///< Called when an incoming update is being processed for access control of each data element.
+        kEvent_UpdateRequestProcessingComplete = 6, ///< Called upon completion of processing of all trait data in the update.
+#endif                                              // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
     };
 
     /**
@@ -124,11 +139,28 @@
         struct
         {
             const TraitCatalogBase<TraitDataSink> * mCatalog; ///< A pointer to the TraitCatalog for the data sinks.
-            const TraitPath *mPath;                           ///< A pointer to the TraitPath being accessed by the
-                                                          ///< subscriptionless notification.
-            const nl::Weave::WeaveMessageInfo * mMsgInfo; ///< A pointer to the message information for the request
+            const TraitPath * mPath;                          ///< A pointer to the TraitPath being accessed by the
+                                                              ///< subscriptionless notification.
+            const nl::Weave::WeaveMessageInfo * mMsgInfo;     ///< A pointer to the message information for the request
         } mDataElementAccessControlForNotification;
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
+
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+        struct
+        {
+            WEAVE_ERROR processingError;                  ///< The WEAVE_ERROR encountered in processing the
+                                                          ///< Update Request.
+            const nl::Weave::WeaveMessageInfo * mMsgInfo; ///< A pointer to the message information for the request
+        } mIncomingUpdateRequest;
+
+        struct
+        {
+            const TraitCatalogBase<TraitDataSource> * mCatalog; ///< A pointer to the TraitCatalog for the data sources.
+            const TraitPath * mPath;                            ///< A pointer to the TraitPath being accessed by the
+                                                                ///< update request.
+            const nl::Weave::WeaveMessageInfo * mMsgInfo;       ///< A pointer to the message information for the request
+        } mDataElementAccessControlForUpdateRequest;
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
     };
 
     /**
@@ -158,15 +190,28 @@
 #if WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
         struct
         {
-            bool mShouldContinueProcessing;      ///< Set to true if subscriptionless notification is allowed.
+            bool mShouldContinueProcessing; ///< Set to true if subscriptionless notification is allowed.
         } mIncomingSubscriptionlessNotification;
 
         struct
         {
-            bool mRejectNotification;      ///< Set to true if subscriptionless notification is rejected.
-            WEAVE_ERROR mReason;           ///< The reason for the rejection, if any.
+            bool mRejectNotification; ///< Set to true if subscriptionless notification is rejected.
+            WEAVE_ERROR mReason;      ///< The reason for the rejection, if any.
         } mDataElementAccessControlForNotification;
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
+
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+        struct
+        {
+            bool mShouldContinueProcessing; ///< Set to true if update is allowed.
+        } mIncomingUpdateRequest;
+
+        struct
+        {
+            bool mRejectUpdateRequest; ///< Set to true if update is rejected.
+            WEAVE_ERROR mReason;       ///< The reason for the rejection, if any.
+        } mDataElementAccessControlForUpdateRequest;
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
     };
 
     /**
@@ -253,8 +298,7 @@
     WEAVE_ERROR NewClient(SubscriptionClient ** const appClient, Binding * const apBinding, void * const apAppState,
                           SubscriptionClient::EventCallback const aEventCallback,
                           const TraitCatalogBase<TraitDataSink> * const apCatalog,
-                          const uint32_t aInactivityTimeoutDuringSubscribingMsec,
-                          IWeaveWDMMutex * aUpdateMutex);
+                          const uint32_t aInactivityTimeoutDuringSubscribingMsec, IWeaveWDMMutex * aUpdateMutex);
 
     WEAVE_ERROR NewSubscriptionHandler(SubscriptionHandler ** const subHandler);
 
@@ -301,8 +345,7 @@
                      const EventCallback aEventCallback = NULL);
 
 #if WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
-    WEAVE_ERROR RegisterForSubscriptionlessNotifications(
-                     const TraitCatalogBase<TraitDataSink> * const apCatalog);
+    WEAVE_ERROR RegisterForSubscriptionlessNotifications(const TraitCatalogBase<TraitDataSink> * const apCatalog);
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
 
     nl::Weave::WeaveExchangeManager * GetExchangeManager(void) const { return mExchangeMgr; };
@@ -342,16 +385,12 @@
     class SubscriptionlessNotifyDataElementAccessControlDelegate : public IDataElementAccessControlDelegate
     {
     public:
-         SubscriptionlessNotifyDataElementAccessControlDelegate(const WeaveMessageInfo * aMsgInfo)
-         {
-             mMsgInfo = aMsgInfo;
-         }
+        SubscriptionlessNotifyDataElementAccessControlDelegate(const WeaveMessageInfo * aMsgInfo) { mMsgInfo = aMsgInfo; }
 
-         WEAVE_ERROR DataElementAccessCheck(const TraitPath & aTraitPath,
-                                            const TraitCatalogBase<TraitDataSink> & aCatalog);
+        WEAVE_ERROR DataElementAccessCheck(const TraitPath & aTraitPath, const TraitCatalogBase<TraitDataSink> & aCatalog);
 
     private:
-         const WeaveMessageInfo * mMsgInfo;
+        const WeaveMessageInfo * mMsgInfo;
     };
 
     static void OnSubscriptionlessNotification(nl::Weave::ExchangeContext * aEC, const nl::Inet::IPPacketInfo * aPktInfo,
@@ -359,6 +398,23 @@
                                                PacketBuffer * aPayload);
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    class UpdateRequestDataElementAccessControlDelegate : public IUpdateRequestDataElementAccessControlDelegate
+    {
+    public:
+        UpdateRequestDataElementAccessControlDelegate(const WeaveMessageInfo * aMsgInfo) { mMsgInfo = aMsgInfo; }
+
+        WEAVE_ERROR DataElementAccessCheck(const TraitPath & aTraitPath, const TraitCatalogBase<TraitDataSource> & aCatalog);
+
+    private:
+        const WeaveMessageInfo * mMsgInfo;
+    };
+
+    static void OnUpdateRequest(nl::Weave::ExchangeContext * apEC, const nl::Inet::IPPacketInfo * aPktInfo,
+                                const nl::Weave::WeaveMessageInfo * aMsgInfo, uint32_t aProfileId, uint8_t aMsgType,
+                                PacketBuffer * aPayload);
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 #if WDM_ENABLE_SUBSCRIPTION_CLIENT
     // Client-specific features
 
@@ -370,11 +426,54 @@
 
 #endif // WDM_ENABLE_SUBSCRIPTION_CLIENT
 
-    static WEAVE_ERROR ProcessDataList(nl::Weave::TLV::TLVReader & aReader,
-                                       const TraitCatalogBase<TraitDataSink> * aCatalog,
-                                       bool & aOutIsPartialChange,
-                                       TraitDataHandle & aOutTraitDataHandle,
+    static WEAVE_ERROR ProcessDataList(nl::Weave::TLV::TLVReader & aReader, const TraitCatalogBase<TraitDataSink> * aCatalog,
+                                       bool & aOutIsPartialChange, TraitDataHandle & aOutTraitDataHandle,
                                        IDataElementAccessControlDelegate & acDelegate);
+
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    struct StatusDataHandleElement
+    {
+        uint32_t mProfileId;
+        uint16_t mStatusCode;
+        TraitDataHandle mTraitDataHandle;
+    };
+
+    struct UpdateResponseWriterContext
+    {
+        void * mpFirstStatusDataHandleElement;
+        const TraitCatalogBase<TraitDataSource> * mpCatalog;
+        uint32_t mNumDataElements;
+    };
+
+    static WEAVE_ERROR AllocateRightSizedBuffer(PacketBuffer *& buf, const uint32_t desiredSize, const uint32_t minSize,
+                                                uint32_t & outMaxPayloadSize);
+    static void ConstructStatusListVersionList(Weave::TLV::TLVWriter & aWriter, void * apContext);
+    static void BuildStatusDataHandleElement(PacketBuffer * pBuf, TraitDataHandle aTraitDataHandle, WEAVE_ERROR & err,
+                                             uint32_t aCurrentIndex);
+    static bool IsStartingPath(StatusDataHandleElement * apStatusDataHandleList, TraitDataHandle aTraitDataHandle,
+                               uint32_t aCurrentIndex);
+    static WEAVE_ERROR UpdateTraitVersions(PacketBuffer * apBuf, const TraitCatalogBase<TraitDataSource> * apCatalog,
+                                           uint32_t aNumDataElements);
+    static WEAVE_ERROR SendFaultyUpdateResponse(Weave::ExchangeContext * apEC);
+    static WEAVE_ERROR SendUpdateResponse(Weave::ExchangeContext * apEC, uint32_t aNumDataElements,
+                                          const TraitCatalogBase<TraitDataSource> * apCatalog, PacketBuffer * apBuf,
+                                          bool existFailure, uint32_t aMaxPayloadSize);
+    static WEAVE_ERROR ProcessUpdateRequestDataElement(Weave::TLV::TLVReader & aReader, TraitDataHandle & aHandle,
+                                                       PropertyPathHandle & aPathHandle,
+                                                       const TraitCatalogBase<TraitDataSource> * apCatalog,
+                                                       IUpdateRequestDataElementAccessControlDelegate & acDelegate,
+                                                       bool aConditionalLoop, uint32_t aCurrentIndex, bool & aExistFailure,
+                                                       PacketBuffer * apBuf);
+    static WEAVE_ERROR ProcessUpdateRequestDataList(Weave::TLV::TLVReader & aReader, PacketBuffer * apBuf,
+                                                    const TraitCatalogBase<TraitDataSource> * apCatalog,
+                                                    IUpdateRequestDataElementAccessControlDelegate & acDelegate,
+                                                    bool & aExistFailure, uint32_t & aNumDataElements, bool aConditionalLoop);
+
+    static WEAVE_ERROR ProcessUpdateRequest(Weave::ExchangeContext * apEC, Weave::TLV::TLVReader & aReader,
+                                            const TraitCatalogBase<TraitDataSource> * apCatalog,
+                                            IUpdateRequestDataElementAccessControlDelegate & acDelegate);
+
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
 #if WEAVE_DETAIL_LOGGING
     void LogSubscriptionFreed(void) const;
 #endif // #if WEAVE_DETAIL_LOGGING
diff --git a/src/lib/profiles/data-management/Current/TraitData.cpp b/src/lib/profiles/data-management/Current/TraitData.cpp
index 6c1ebd9..7b73cd5 100644
--- a/src/lib/profiles/data-management/Current/TraitData.cpp
+++ b/src/lib/profiles/data-management/Current/TraitData.cpp
@@ -1,6 +1,7 @@
 /*
  *
- *    Copyright (c) 2016-2017 Nest Labs, Inc.
+ *    Copyright (c) 2016-2018 Nest Labs, Inc.
+ *    Copyright (c) 2019-2020 Google, LLC.
  *    All rights reserved.
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,16 +45,15 @@
 using namespace ::nl::Weave::Profiles::DataManagement;
 using namespace ::nl::Weave::Profiles::DataManagement_Current;
 
-UpdateDirtyPathFilter::UpdateDirtyPathFilter(SubscriptionClient *apSubClient,
-                                             TraitDataHandle traitDataHandle,
+UpdateDirtyPathFilter::UpdateDirtyPathFilter(SubscriptionClient * apSubClient, TraitDataHandle traitDataHandle,
                                              const TraitSchemaEngine * aEngine)
 {
-    mpSubClient = apSubClient;
+    mpSubClient      = apSubClient;
     mTraitDataHandle = traitDataHandle;
-    mSchemaEngine = aEngine;
+    mSchemaEngine    = aEngine;
 }
 
-bool UpdateDirtyPathFilter::FilterPath (PropertyPathHandle pathhandle)
+bool UpdateDirtyPathFilter::FilterPath(PropertyPathHandle pathhandle)
 {
     bool retval = false;
 
@@ -71,11 +71,11 @@
 
 UpdateDictionaryDirtyPathCut::UpdateDictionaryDirtyPathCut(TraitDataHandle aTraitDataHandle, UpdateEncoder * apEncoder)
 {
-    mpUpdateEncoder = apEncoder;
+    mpUpdateEncoder  = apEncoder;
     mTraitDataHandle = aTraitDataHandle;
 }
 
-WEAVE_ERROR UpdateDictionaryDirtyPathCut::CutPath (PropertyPathHandle aPathhandle, const TraitSchemaEngine * apEngine)
+WEAVE_ERROR UpdateDictionaryDirtyPathCut::CutPath(PropertyPathHandle aPathhandle, const TraitSchemaEngine * apEngine)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     // TODO: rename this struct, and pass apEngine to the constructor.
@@ -88,14 +88,14 @@
     return err;
 }
 
-WEAVE_ERROR TraitSchemaEngine::ParseTagString(const char *apTagString, char **apEndptr, uint8_t& aParseRes) const
+WEAVE_ERROR TraitSchemaEngine::ParseTagString(const char * apTagString, char ** apEndptr, uint8_t & aParseRes) const
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
 
     VerifyOrExit(apTagString != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
     VerifyOrExit(*apTagString == '/', err = WEAVE_ERROR_INVALID_ARGUMENT);
 
-    apTagString ++;
+    apTagString++;
 
     aParseRes = strtoul(apTagString, apEndptr, 0);
     VerifyOrExit(!(*apEndptr == apTagString || (**apEndptr != '\0' && **apEndptr != '/')), err = WEAVE_ERROR_INVALID_ARGUMENT);
@@ -109,9 +109,9 @@
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     PropertyPathHandle childProperty, curProperty;
-    char *parseEnd;
+    char * parseEnd;
     uint8_t parseRes = 0;
-    uint64_t tag = 0;
+    uint64_t tag     = 0;
 
     VerifyOrExit(aPathString != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
 
@@ -362,10 +362,8 @@
 }
 
 #if WEAVE_CONFIG_ENABLE_WDM_UPDATE
-WEAVE_ERROR TraitSchemaEngine::RetrieveUpdatableDictionaryData(PropertyPathHandle aHandle,
-                                                               uint64_t aTagToWrite,
-                                                               TLVWriter & aWriter,
-                                                               IGetDataDelegate * aDelegate,
+WEAVE_ERROR TraitSchemaEngine::RetrieveUpdatableDictionaryData(PropertyPathHandle aHandle, uint64_t aTagToWrite,
+                                                               TLVWriter & aWriter, IGetDataDelegate * aDelegate,
                                                                PropertyPathHandle & aPropertyPathHandleOfDictItemToStartFrom) const
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
@@ -373,8 +371,8 @@
 #if TDM_ENABLE_PUBLISHER_DICTIONARY_SUPPORT
     nl::Weave::TLV::TLVType dataContainerType;
     PropertyDictionaryKey dictionaryItemKey;
-    uintptr_t context = 0;
-    uint32_t numKeysEncoded = 0;
+    uintptr_t context                               = 0;
+    uint32_t numKeysEncoded                         = 0;
     PropertySchemaHandle dictionaryItemSchemaHandle = GetPropertySchemaHandle(GetFirstChild(aHandle));
     PropertyPathHandle dictionaryItemPathHandle;
     PropertyPathHandle itemToSkipTo = aPropertyPathHandleOfDictItemToStartFrom;
@@ -385,8 +383,7 @@
     // items.
     aPropertyPathHandleOfDictItemToStartFrom = kNullPropertyPathHandle;
 
-    err = aWriter.StartContainer(aTagToWrite,
-            nl::Weave::TLV::kTLVType_Structure, dataContainerType);
+    err = aWriter.StartContainer(aTagToWrite, nl::Weave::TLV::kTLVType_Structure, dataContainerType);
     SuccessOrExit(err);
 
     while ((err = aDelegate->GetNextDictionaryItemKey(aHandle, context, dictionaryItemKey)) == WEAVE_NO_ERROR)
@@ -407,18 +404,18 @@
         err = RetrieveData(dictionaryItemPathHandle, tag, aWriter, aDelegate);
         if (err != WEAVE_NO_ERROR)
         {
-            WeaveLogDetail(DataManagement, "Dictionary item whith path 0x%" PRIx32 ", tag 0x% " PRIx64 " failed with error % " PRIu32 "",
-                    dictionaryItemPathHandle, tag, err);
+            WeaveLogDetail(DataManagement,
+                           "Dictionary item whith path 0x%" PRIx32 ", tag 0x% " PRIx64 " failed with error % " PRIu32 "",
+                           dictionaryItemPathHandle, tag, err);
         }
-        if (numKeysEncoded > 0 &&
-                ((err == WEAVE_ERROR_BUFFER_TOO_SMALL) || (err == WEAVE_ERROR_NO_MEMORY)))
+        if (numKeysEncoded > 0 && ((err == WEAVE_ERROR_BUFFER_TOO_SMALL) || (err == WEAVE_ERROR_NO_MEMORY)))
         {
             // BUFFER_TOO_SMALL means there is no more space in the current buffer.
             // NO_MEMORY means the application is trying to build a chain of pBufs, but
             // there are no more buffers.
-            aWriter = backupWriter;
+            aWriter                                  = backupWriter;
             aPropertyPathHandleOfDictItemToStartFrom = dictionaryItemPathHandle;
-            err = WEAVE_NO_ERROR;
+            err                                      = WEAVE_NO_ERROR;
             break;
         }
         SuccessOrExit(err);
@@ -440,13 +437,11 @@
     return err;
 }
 
-WEAVE_ERROR TraitSchemaEngine::GetRelativePathTags(const PropertyPathHandle aCandidateHandle,
-                                                   uint64_t *aTags,
-                                                   const uint32_t aTagsSize,
-                                                   uint32_t &aNumTags) const
+WEAVE_ERROR TraitSchemaEngine::GetRelativePathTags(const PropertyPathHandle aCandidateHandle, uint64_t * aTags,
+                                                   const uint32_t aTagsSize, uint32_t & aNumTags) const
 {
     PropertyPathHandle pathWalkStore[mSchema.mTreeDepth];
-    uint32_t pathWalkDepth         = 0;
+    uint32_t pathWalkDepth = 0;
     PropertyPathHandle curProperty;
     WEAVE_ERROR err = WEAVE_NO_ERROR;
 
@@ -468,7 +463,7 @@
         while (pathWalkDepth)
         {
             PropertyPathHandle curHandle = pathWalkStore[pathWalkDepth - 1];
-            aTags[aNumTags] = GetTag(curHandle);
+            aTags[aNumTags]              = GetTag(curHandle);
             pathWalkDepth--;
             aNumTags++;
         }
@@ -479,7 +474,8 @@
 }
 #endif // WEAVE_CONFIG_ENABLE_WDM_UPDATE
 
-WEAVE_ERROR TraitSchemaEngine::StoreData(PropertyPathHandle aHandle, TLVReader & aReader, ISetDataDelegate * aDelegate, IPathFilter * apPathFilter) const
+WEAVE_ERROR TraitSchemaEngine::StoreData(PropertyPathHandle aHandle, TLVReader & aReader, ISetDataDelegate * aDelegate,
+                                         IPathFilter * apPathFilter) const
 {
     WEAVE_ERROR err                 = WEAVE_NO_ERROR;
     TLVType type                    = kTLVType_NotSpecified;
@@ -498,7 +494,7 @@
     // The logic further below deals with the cases where this function was called on a path handle at the dictionary or higher.
     if (IsInDictionary(curHandle, dictionaryItemHandle))
     {
-        aDelegate->OnDataSinkEvent(ISetDataDelegate::kDataSinkEvent_DictionaryItemModifyBegin, dictionaryItemHandle);
+        aDelegate->OnSetDataEvent(ISetDataDelegate::kSetDataEvent_DictionaryItemModifyBegin, dictionaryItemHandle);
         dictionaryEventSignalled = true;
     }
 
@@ -516,29 +512,40 @@
         // ascension is returning back to a higher point in the tree.
         do
         {
-            if (!(apPathFilter != NULL && apPathFilter->FilterPath(curHandle))) {
+            if (!(apPathFilter != NULL && apPathFilter->FilterPath(curHandle)))
+            {
 #if TDM_DISABLE_STRICT_SCHEMA_COMPLIANCE
                 if (!IsNullPropertyPathHandle(curHandle))
 #endif
                 {
-                    if (!IsLeaf(curHandle)) {
-                        if (descending) {
+                    if (!IsLeaf(curHandle))
+                    {
+                        if (descending)
+                        {
                             bool enterContainer = (aReader.GetType() != kTLVType_Null);
-                            if (enterContainer) {
+                            if (enterContainer)
+                            {
                                 err = aReader.EnterContainer(type);
                                 SuccessOrExit(err);
 
                                 parentHandle = curHandle;
-                            } else {
-                                if (IsNullable(curHandle)) {
+                            }
+                            else
+                            {
+                                if (IsNullable(curHandle))
+                                {
                                     err = aDelegate->SetData(curHandle, aReader, !enterContainer);
-                                } else {
+                                }
+                                else
+                                {
                                     err = WEAVE_ERROR_WDM_SCHEMA_MISMATCH;
                                 }
                                 SuccessOrExit(err);
                             }
                         }
-                    } else {
+                    }
+                    else
+                    {
                         err = aDelegate->SetData(curHandle, aReader, aReader.GetType() == kTLVType_Null);
                         SuccessOrExit(err);
 
@@ -548,18 +555,22 @@
                     }
                 }
 
-                if (!descending) {
-                    if (IsDictionary(curHandle)) {
+                if (!descending)
+                {
+                    if (IsDictionary(curHandle))
+                    {
                         // We can surmise this is a replace if we're ascending to a node that is a dictionary, and that node
                         // is lower than the target node this function was directed at (we can't get to this point in code if the
                         // two handles (target and current) are equivalent to each other).
-                        aDelegate->OnDataSinkEvent(ISetDataDelegate::kDataSinkEvent_DictionaryReplaceEnd, curHandle);
-                    } else if (IsDictionary(parentHandle)) {
-                        // We can surmise this is a modify/add if we're ascending to a node whose parent is a dictionary, and that node
-                        // is lower than the target node this function was directed at (we can't get to this point in code if the
-                        // two handles (target and current) are equivalent to each other). Those cases are handled by the two 'if'
-                        // statements at the top and bottom of this function.
-                        aDelegate->OnDataSinkEvent(ISetDataDelegate::kDataSinkEvent_DictionaryItemModifyEnd, curHandle);
+                        aDelegate->OnSetDataEvent(ISetDataDelegate::kSetDataEvent_DictionaryReplaceEnd, curHandle);
+                    }
+                    else if (IsDictionary(parentHandle))
+                    {
+                        // We can surmise this is a modify/add if we're ascending to a node whose parent is a dictionary, and that
+                        // node is lower than the target node this function was directed at (we can't get to this point in code if
+                        // the two handles (target and current) are equivalent to each other). Those cases are handled by the two
+                        // 'if' statements at the top and bottom of this function.
+                        aDelegate->OnSetDataEvent(ISetDataDelegate::kSetDataEvent_DictionaryItemModifyEnd, curHandle);
                     }
                 }
             }
@@ -568,45 +579,54 @@
             err = aReader.Next();
             VerifyOrExit((err == WEAVE_NO_ERROR) || (err == WEAVE_END_OF_TLV), );
 
-            if (err == WEAVE_END_OF_TLV) {
+            if (err == WEAVE_END_OF_TLV)
+            {
                 // We've hit the end of the container - exit out and point our current handle to its parent.
                 // In the process, restore the parentHandle as well.
                 err = aReader.ExitContainer(type);
                 SuccessOrExit(err);
 
-                curHandle = parentHandle;
+                curHandle    = parentHandle;
                 parentHandle = GetParent(curHandle);
 
                 descending = false;
-            } else {
+            }
+            else
+            {
                 const uint64_t tag = aReader.GetTag();
 
                 descending = true;
 
-                if (IsProfileTag(tag)) {
-                    VerifyOrExit(ProfileIdFromTag(tag) == kWeaveProfile_DictionaryKey,
-                                 err = WEAVE_ERROR_INVALID_TLV_TAG);
+                if (IsProfileTag(tag))
+                {
+                    VerifyOrExit(ProfileIdFromTag(tag) == kWeaveProfile_DictionaryKey, err = WEAVE_ERROR_INVALID_TLV_TAG);
                     curHandle = GetDictionaryItemHandle(parentHandle, TagNumFromTag(tag));
-                } else {
+                }
+                else
+                {
                     curHandle = GetChildHandle(parentHandle, TagNumFromTag(tag));
                 }
 
-                if (!(apPathFilter != NULL && apPathFilter->FilterPath(curHandle))) {
-                    if (IsDictionary(curHandle)) {
+                if (!(apPathFilter != NULL && apPathFilter->FilterPath(curHandle)))
+                {
+                    if (IsDictionary(curHandle))
+                    {
                         // If we're descending onto a node that is a dictionary, we know for certain that it is a replace operation
                         // since the target path handle for this function was higher in the tree than the node representing the
                         // dictionary itself.
-                        aDelegate->OnDataSinkEvent(ISetDataDelegate::kDataSinkEvent_DictionaryReplaceBegin, curHandle);
-                    } else if (IsDictionary(parentHandle)) {
+                        aDelegate->OnSetDataEvent(ISetDataDelegate::kSetDataEvent_DictionaryReplaceBegin, curHandle);
+                    }
+                    else if (IsDictionary(parentHandle))
+                    {
                         // Alternatively, if we're descending onto a node whose parent is a dictionary, we know that this node
-                        // represents an element in the dictionary and as such, is an appropriate point in the traversal to notify the
-                        // application of an upcoming dictionary item modification/insertion.
-                        aDelegate->OnDataSinkEvent(ISetDataDelegate::kDataSinkEvent_DictionaryItemModifyBegin,
-                                                   curHandle);
+                        // represents an element in the dictionary and as such, is an appropriate point in the traversal to notify
+                        // the application of an upcoming dictionary item modification/insertion.
+                        aDelegate->OnSetDataEvent(ISetDataDelegate::kSetDataEvent_DictionaryItemModifyBegin, curHandle);
                     }
                 }
 #if !TDM_DISABLE_STRICT_SCHEMA_COMPLIANCE
-                if (IsNullPropertyPathHandle(curHandle)) {
+                if (IsNullPropertyPathHandle(curHandle))
+                {
                     err = WEAVE_ERROR_TLV_TAG_NOT_FOUND;
                     break;
                 }
@@ -617,7 +637,7 @@
 
     if (dictionaryEventSignalled)
     {
-        aDelegate->OnDataSinkEvent(ISetDataDelegate::kDataSinkEvent_DictionaryItemModifyEnd, dictionaryItemHandle);
+        aDelegate->OnSetDataEvent(ISetDataDelegate::kSetDataEvent_DictionaryItemModifyEnd, dictionaryItemHandle);
     }
 
 exit:
@@ -633,8 +653,7 @@
 {
     bool retval = false;
 
-    VerifyOrExit(aChildHandle != kNullPropertyPathHandle &&
-                 aParentHandle != kNullPropertyPathHandle, );
+    VerifyOrExit(aChildHandle != kNullPropertyPathHandle && aParentHandle != kNullPropertyPathHandle, );
 
     do
     {
@@ -996,15 +1015,15 @@
     {
         if (aVersion != mVersion)
         {
-            WeaveLogDetail(DataManagement, "Trait %08x version: 0x%" PRIx64 " -> 0x%" PRIx64 "", mSchemaEngine->GetProfileId(), mVersion,
-                    aVersion);
+            WeaveLogDetail(DataManagement, "Trait %08x version: 0x%" PRIx64 " -> 0x%" PRIx64 "", mSchemaEngine->GetProfileId(),
+                           mVersion, aVersion);
         }
     }
     else
     {
         WeaveLogDetail(DataManagement, "Trait %08x version: n/a -> 0x%" PRIx64 "", mSchemaEngine->GetProfileId(), aVersion);
     }
-    mVersion = aVersion;
+    mVersion         = aVersion;
     mHasValidVersion = true;
 }
 
@@ -1016,8 +1035,8 @@
 
 void TraitDataSink::SetLastNotifyVersion(uint64_t aVersion)
 {
-    WeaveLogDetail(DataManagement, "Trait %08x last notify version: 0x%" PRIx64 " -> 0x%" PRIx64 "", mSchemaEngine->GetProfileId(), mLastNotifyVersion,
-            aVersion);
+    WeaveLogDetail(DataManagement, "Trait %08x last notify version: 0x%" PRIx64 " -> 0x%" PRIx64 "", mSchemaEngine->GetProfileId(),
+                   mLastNotifyVersion, aVersion);
 
     mLastNotifyVersion = aVersion;
 }
@@ -1027,10 +1046,10 @@
 
 TraitDataSink::TraitDataSink(const TraitSchemaEngine * aEngine)
 {
-    mSchemaEngine    = aEngine;
-    mVersion         = 0;
+    mSchemaEngine      = aEngine;
+    mVersion           = 0;
     mLastNotifyVersion = 0;
-    mHasValidVersion = 0;
+    mHasValidVersion   = 0;
 }
 
 WEAVE_ERROR TraitDataSink::StoreDataElement(PropertyPathHandle aHandle, TLVReader & aReader, uint8_t aFlags,
@@ -1130,8 +1149,8 @@
     }
     else
     {
-        WeaveLogDetail(DataManagement, "<StoreData> [Trait %08x] version: 0x%" PRIx64 " (no-change)",
-                       mSchemaEngine->GetProfileId(), mVersion);
+        WeaveLogDetail(DataManagement, "<StoreData> [Trait %08x] version: 0x%" PRIx64 " (no-change)", mSchemaEngine->GetProfileId(),
+                       mVersion);
     }
 
     if (aFlags & kLastElementInChange)
@@ -1143,25 +1162,25 @@
     return err;
 }
 
-void TraitDataSink::OnDataSinkEvent(DataSinkEventType aEventType, PropertyPathHandle aHandle)
+void TraitDataSink::OnSetDataEvent(SetDataEventType aEventType, PropertyPathHandle aHandle)
 {
     EventType event;
 
     switch (aEventType)
     {
-    case kDataSinkEvent_DictionaryReplaceBegin:
+    case kSetDataEvent_DictionaryReplaceBegin:
         event = kEventDictionaryReplaceBegin;
         break;
 
-    case kDataSinkEvent_DictionaryReplaceEnd:
+    case kSetDataEvent_DictionaryReplaceEnd:
         event = kEventDictionaryReplaceEnd;
         break;
 
-    case kDataSinkEvent_DictionaryItemModifyBegin:
+    case kSetDataEvent_DictionaryItemModifyBegin:
         event = kEventDictionaryItemModifyBegin;
         break;
 
-    case kDataSinkEvent_DictionaryItemModifyEnd:
+    case kSetDataEvent_DictionaryItemModifyEnd:
         event = kEventDictionaryItemModifyEnd;
         break;
 
@@ -1215,8 +1234,9 @@
 
 uint64_t TraitDataSource::GetVersion(void)
 {
-    // At the time of version retrieval, check to see if the version is still at the sentinel value of 0 (indicating 'no version') set at construction. If it is,
-    // it means that the data source has not over-ridden the version to something other than 0, indicating that it desires to use randomized data versions.
+    // At the time of version retrieval, check to see if the version is still at the sentinel value of 0 (indicating 'no version')
+    // set at construction. If it is, it means that the data source has not over-ridden the version to something other than 0,
+    // indicating that it desires to use randomized data versions.
     while (mVersion == 0)
     {
         mVersion = GetRandU64();
@@ -1263,8 +1283,7 @@
  *  object.
  */
 void TraitDataSource::OnCustomCommand(Command * aCommand, const nl::Weave::WeaveMessageInfo * aMsgInfo,
-                                      nl::Weave::PacketBuffer * aPayload,
-                                      nl::Weave::TLV::TLVReader & aArgumentReader)
+                                      nl::Weave::PacketBuffer * aPayload, nl::Weave::TLV::TLVReader & aArgumentReader)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
 
@@ -1344,27 +1363,33 @@
     return SubscriptionEngine::GetInstance()->Unlock();
 }
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+WEAVE_ERROR TraitDataSource::Unlock(bool aSkipVersionIncrement)
+{
+    if (mManagedVersion && mSetDirtyCalled && !aSkipVersionIncrement)
+    {
+        IncrementVersion();
+    }
+
+    VerifyOrDie(SubscriptionEngine::GetInstance());
+    return SubscriptionEngine::GetInstance()->Unlock();
+}
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 #if WEAVE_CONFIG_ENABLE_WDM_UPDATE
 TraitUpdatableDataSink::TraitUpdatableDataSink(const TraitSchemaEngine * aEngine) :
-    TraitDataSink(aEngine),
-    mUpdateRequiredVersion(0),
-    mUpdateStartVersion(0),
-    mConditionalUpdate(false),
-    mPotentialDataLoss(false),
-    mpSubClient(NULL),
-    mpUpdateEncoder(NULL)
-{
-};
+    TraitDataSink(aEngine), mUpdateRequiredVersion(0), mUpdateStartVersion(0), mConditionalUpdate(false), mPotentialDataLoss(false),
+    mpSubClient(NULL), mpUpdateEncoder(NULL) { };
 
 void TraitUpdatableDataSink::Lock(SubscriptionClient * apSubClient)
 {
-    VerifyOrDie(apSubClient!=NULL);
+    VerifyOrDie(apSubClient != NULL);
     apSubClient->LockUpdateMutex();
 }
 
 void TraitUpdatableDataSink::Unlock(SubscriptionClient * apSubClient)
 {
-    VerifyOrDie(apSubClient!=NULL);
+    VerifyOrDie(apSubClient != NULL);
     apSubClient->UnlockUpdateMutex();
 }
 
@@ -1383,12 +1408,12 @@
     return err;
 }
 
-void TraitUpdatableDataSink::SetUpdateRequiredVersion(const uint64_t &aUpdateRequiredVersion)
+void TraitUpdatableDataSink::SetUpdateRequiredVersion(const uint64_t & aUpdateRequiredVersion)
 {
     if (aUpdateRequiredVersion != mUpdateRequiredVersion)
     {
         WeaveLogDetail(DataManagement, "[Trait %08x] UpdateRequiredVersion: 0x%" PRIx64 " -> 0x%" PRIx64 "",
-                mSchemaEngine->GetProfileId(), mUpdateRequiredVersion, aUpdateRequiredVersion);
+                       mSchemaEngine->GetProfileId(), mUpdateRequiredVersion, aUpdateRequiredVersion);
         mUpdateRequiredVersion = aUpdateRequiredVersion;
 
         // TODO: Ideally, this fault would be injected when the payload is encoded; but, all DataElements for the
@@ -1406,16 +1431,13 @@
     if (GetVersion() != mUpdateStartVersion)
     {
         WeaveLogDetail(DataManagement, "[Trait %08x] UpdateStartVersion: 0x%" PRIx64 " -> 0x%" PRIx64 "",
-                mSchemaEngine->GetProfileId(), mUpdateStartVersion, GetVersion());
+                       mSchemaEngine->GetProfileId(), mUpdateStartVersion, GetVersion());
         mUpdateStartVersion = GetVersion();
     }
 }
 
-WEAVE_ERROR TraitUpdatableDataSink::ReadData(TraitDataHandle aTraitDataHandle,
-                                             PropertyPathHandle aHandle,
-                                             uint64_t aTagToWrite,
-                                             TLVWriter & aWriter,
-                                             PropertyPathHandle & aPropertyPathHandleOfDictItemToStartFrom)
+WEAVE_ERROR TraitUpdatableDataSink::ReadData(TraitDataHandle aTraitDataHandle, PropertyPathHandle aHandle, uint64_t aTagToWrite,
+                                             TLVWriter & aWriter, PropertyPathHandle & aPropertyPathHandleOfDictItemToStartFrom)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
 
@@ -1423,14 +1445,13 @@
     {
         WeaveLogDetail(DataManagement, "process dictionary in update");
         err = mSchemaEngine->RetrieveUpdatableDictionaryData(aHandle, aTagToWrite, aWriter,
-                                                             static_cast<TraitSchemaEngine::IGetDataDelegate*>(this),
+                                                             static_cast<TraitSchemaEngine::IGetDataDelegate *>(this),
                                                              aPropertyPathHandleOfDictItemToStartFrom);
     }
     else
     {
         UpdateDictionaryDirtyPathCut updateDirtyPathCut(aTraitDataHandle, GetUpdateEncoder());
-        err = mSchemaEngine->RetrieveData(aHandle, aTagToWrite, aWriter,
-                                          static_cast<TraitSchemaEngine::IGetDataDelegate *>(this),
+        err = mSchemaEngine->RetrieveData(aHandle, aTagToWrite, aWriter, static_cast<TraitSchemaEngine::IGetDataDelegate *>(this),
                                           &updateDirtyPathCut);
     }
     SuccessOrExit(err);
@@ -1467,7 +1488,8 @@
  * @retval      WEAVE_ERROR_WDM_PATH_STORE_FULL if there is no memory to store the path.
  * @retval      Other WEAVE_ERROR codes depending on the failure.
  */
-WEAVE_ERROR TraitUpdatableDataSink::SetUpdated(SubscriptionClient * apSubClient, PropertyPathHandle aPropertyHandle, bool aIsConditional)
+WEAVE_ERROR TraitUpdatableDataSink::SetUpdated(SubscriptionClient * apSubClient, PropertyPathHandle aPropertyHandle,
+                                               bool aIsConditional)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
 
@@ -1479,5 +1501,120 @@
 exit:
     return err;
 }
-
 #endif // WEAVE_CONFIG_ENABLE_WDM_UPDATE
+
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+TraitUpdatableDataSource::OnChangeRejection TraitUpdatableDataSource::sChangeRejectionCb = NULL;
+void * TraitUpdatableDataSource::sChangeRejectionContext                                 = NULL;
+
+TraitUpdatableDataSource::TraitUpdatableDataSource(const TraitSchemaEngine * aEngine) : TraitDataSource(aEngine) { }
+
+WEAVE_ERROR TraitUpdatableDataSource::StoreDataElement(PropertyPathHandle aHandle, TLVReader & aReader, uint8_t aFlags,
+                                                       OnChangeRejection aFunc, void * aContext)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    DataElement::Parser parser;
+    bool dataPresent = false, deletePresent = false;
+
+    err = parser.Init(aReader);
+    SuccessOrExit(err);
+
+    err = parser.CheckPresence(&dataPresent, &deletePresent);
+    SuccessOrExit(err);
+
+    if (deletePresent)
+    {
+        err = parser.GetDeletedDictionaryKeys(&aReader);
+        SuccessOrExit(err);
+
+        while ((err = aReader.Next()) == WEAVE_NO_ERROR)
+        {
+            PropertyDictionaryKey key;
+            PropertyPathHandle handle;
+
+            err = aReader.Get(key);
+            SuccessOrExit(err);
+
+            // In the case of a delete, the path is usually directed to the dictionary itself. We
+            // need to get the handle to the child dictionary element handle first before we can
+            // pass it up to the application.
+            handle = mSchemaEngine->GetFirstChild(aHandle);
+            VerifyOrExit(handle != kNullPropertyPathHandle, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+            handle = CreatePropertyPathHandle(GetPropertySchemaHandle(handle), key);
+            OnEvent(kEventDictionaryItemDelete, &handle);
+        }
+
+        VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV, );
+        err = WEAVE_NO_ERROR;
+    }
+
+    if (aHandle != kNullPropertyPathHandle && dataPresent)
+    {
+        err = parser.GetData(&aReader);
+        SuccessOrExit(err);
+        err = mSchemaEngine->StoreData(aHandle, aReader, this, NULL);
+        SuccessOrExit(err);
+    }
+
+exit:
+    return err;
+}
+
+void TraitUpdatableDataSource::OnSetDataEvent(SetDataEventType aEventType, PropertyPathHandle aHandle)
+{
+    EventType event;
+
+    switch (aEventType)
+    {
+    case kSetDataEvent_DictionaryReplaceBegin:
+        event = kEventDictionaryReplaceBegin;
+        break;
+
+    case kSetDataEvent_DictionaryReplaceEnd:
+        event = kEventDictionaryReplaceEnd;
+        break;
+
+    case kSetDataEvent_DictionaryItemModifyBegin:
+        event = kEventDictionaryItemModifyBegin;
+        break;
+
+    case kSetDataEvent_DictionaryItemModifyEnd:
+        event = kEventDictionaryItemModifyEnd;
+        break;
+
+    default:
+        return;
+    };
+
+    OnEvent(event, &aHandle);
+}
+
+void TraitUpdatableDataSource::RejectChange(uint16_t aRejectionStatusCode)
+{
+    if (sChangeRejectionCb)
+    {
+        sChangeRejectionCb(aRejectionStatusCode, GetVersion(), sChangeRejectionContext);
+    }
+}
+
+WEAVE_ERROR TraitUpdatableDataSource::SetData(PropertyPathHandle aHandle, TLVReader & aReader, bool aIsNull)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    // if a trait has no nullable handles, aIsNull will always be false
+    // and serves no purpose. this is true for the default implementation.
+    IgnoreUnusedVariable(aIsNull);
+
+    if (mSchemaEngine->IsLeaf(aHandle))
+    {
+        err = SetLeafData(aHandle, aReader);
+        if (err != WEAVE_NO_ERROR)
+        {
+            WeaveLogDetail(DataManagement, "ahandle %u err: %d", aHandle, err);
+        }
+    }
+    return err;
+}
+
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
diff --git a/src/lib/profiles/data-management/Current/TraitData.h b/src/lib/profiles/data-management/Current/TraitData.h
index 2ffde51..2b1b0dd 100644
--- a/src/lib/profiles/data-management/Current/TraitData.h
+++ b/src/lib/profiles/data-management/Current/TraitData.h
@@ -72,7 +72,6 @@
 typedef uint16_t PropertyDictionaryKey;
 typedef uint16_t TraitDataHandle;
 
-
 /* Reserved property path handles that have special meaning */
 enum
 {
@@ -120,15 +119,14 @@
 class UpdateDirtyPathFilter : public IPathFilter
 {
 public:
-    UpdateDirtyPathFilter(SubscriptionClient *apSubClient,
-                          TraitDataHandle traitDataHandle,
+    UpdateDirtyPathFilter(SubscriptionClient * apSubClient, TraitDataHandle traitDataHandle,
                           const TraitSchemaEngine * aSchemaEngine);
-    virtual bool FilterPath (PropertyPathHandle aPathhandle);
+    virtual bool FilterPath(PropertyPathHandle aPathhandle);
 
 private:
-    SubscriptionClient *mpSubClient;
+    SubscriptionClient * mpSubClient;
     TraitDataHandle mTraitDataHandle;
-    const TraitSchemaEngine *mSchemaEngine;
+    const TraitSchemaEngine * mSchemaEngine;
 };
 
 class IDirtyPathCut
@@ -145,11 +143,11 @@
 class UpdateDictionaryDirtyPathCut : public IDirtyPathCut
 {
 public:
-    UpdateDictionaryDirtyPathCut(TraitDataHandle aTraitDataHandle, UpdateEncoder *pEncoder);
-    virtual WEAVE_ERROR CutPath (PropertyPathHandle aPathhandle, const TraitSchemaEngine * apEngine);
+    UpdateDictionaryDirtyPathCut(TraitDataHandle aTraitDataHandle, UpdateEncoder * pEncoder);
+    virtual WEAVE_ERROR CutPath(PropertyPathHandle aPathhandle, const TraitSchemaEngine * apEngine);
 
 private:
-    UpdateEncoder *mpUpdateEncoder;
+    UpdateEncoder * mpUpdateEncoder;
     TraitDataHandle mTraitDataHandle;
 };
 
@@ -183,23 +181,23 @@
     struct Schema
     {
         uint32_t mProfileId;                   ///< The ID of the trait profile.
-        const PropertyInfo * mSchemaHandleTbl; ///< A pointer to the schema handle table, which provides parent info and context tags
-                                               ///< for each schema handle.
+        const PropertyInfo * mSchemaHandleTbl; ///< A pointer to the schema handle table, which provides parent info and context
+                                               ///< tags for each schema handle.
         uint32_t mNumSchemaHandleEntries;      ///< The number of schema handles in this trait.
         uint32_t mTreeDepth;                   ///< The max depth of this schema.
 #if (TDM_EXTENSION_SUPPORT) || (TDM_VERSIONING_SUPPORT)
-        PropertyPathHandle mMaxParentPathHandle;///< Max handle supported by the parent schema
+        PropertyPathHandle mMaxParentPathHandle; ///< Max handle supported by the parent schema
 #endif
-        uint8_t * mIsDictionaryBitfield;       ///< A bitfield indicating whether each schema handle is a dictionary or not.
-        uint8_t * mIsOptionalBitfield;         ///< A bitfield indicating whether each schema handle is optional or not.
-        uint8_t * mIsImplementedBitfield;      ///< A bitfield indicating whether each optional schema handle is implemented or not.
-        uint8_t * mIsNullableBitfield;         ///< A bitfield indicating whether each schema handle is nullable or not.
-        uint8_t * mIsEphemeralBitfield;        ///< A bitfield indicating whether each schema handle is ephemeral or not.
+        uint8_t * mIsDictionaryBitfield;  ///< A bitfield indicating whether each schema handle is a dictionary or not.
+        uint8_t * mIsOptionalBitfield;    ///< A bitfield indicating whether each schema handle is optional or not.
+        uint8_t * mIsImplementedBitfield; ///< A bitfield indicating whether each optional schema handle is implemented or not.
+        uint8_t * mIsNullableBitfield;    ///< A bitfield indicating whether each schema handle is nullable or not.
+        uint8_t * mIsEphemeralBitfield;   ///< A bitfield indicating whether each schema handle is ephemeral or not.
 #if (TDM_EXTENSION_SUPPORT)
-        Schema *mParentSchema;                 ///< A pointer to the parent schema
+        Schema * mParentSchema; ///< A pointer to the parent schema
 #endif
 #if (TDM_VERSIONING_SUPPORT)
-        const ConstSchemaVersionRange *mVersionRange;     ///< Range of versions supported by this trait
+        const ConstSchemaVersionRange * mVersionRange; ///< Range of versions supported by this trait
 #endif
     };
 
@@ -211,19 +209,19 @@
     class ISetDataDelegate
     {
     public:
-        enum DataSinkEventType
+        enum SetDataEventType
         {
             /* Start of replacement of an entire dictionary */
-            kDataSinkEvent_DictionaryReplaceBegin,
+            kSetDataEvent_DictionaryReplaceBegin,
 
             /* End of replacement of an entire dictionary */
-            kDataSinkEvent_DictionaryReplaceEnd,
+            kSetDataEvent_DictionaryReplaceEnd,
 
             /* Start of modification or addition of a dictionary item */
-            kDataSinkEvent_DictionaryItemModifyBegin,
+            kSetDataEvent_DictionaryItemModifyBegin,
 
             /* End of modification or addition of a dictionary item */
-            kDataSinkEvent_DictionaryItemModifyEnd,
+            kSetDataEvent_DictionaryItemModifyEnd,
         };
 
         /**
@@ -260,7 +258,7 @@
          * For dictionary item added/modififed events, these handles are property path handles as they contain the dictionary key as
          * well.
          */
-        virtual void OnDataSinkEvent(DataSinkEventType aType, PropertyPathHandle aHandle) = 0;
+        virtual void OnSetDataEvent(SetDataEventType aType, PropertyPathHandle aHandle) = 0;
     };
 
     class IGetDataDelegate
@@ -366,7 +364,8 @@
      * @retval #WEAVE_NO_ERROR On success.
      * @retval other           Encountered errors parsing/processing the data.
      */
-    WEAVE_ERROR StoreData(PropertyPathHandle aHandle, nl::Weave::TLV::TLVReader & aReader, ISetDataDelegate * aDelegate, IPathFilter * aPathFilter) const;
+    WEAVE_ERROR StoreData(PropertyPathHandle aHandle, nl::Weave::TLV::TLVReader & aReader, ISetDataDelegate * aDelegate,
+                          IPathFilter * aPathFilter) const;
 
     /**
      * Given a path handle and a writer position on the corresponding data element, retrieve leaf data from the source and write it
@@ -376,10 +375,11 @@
      * @retval other           Encountered errors writing out the data.
      */
     WEAVE_ERROR RetrieveData(PropertyPathHandle aHandle, uint64_t aTagToWrite, nl::Weave::TLV::TLVWriter & aWriter,
-                             IGetDataDelegate * aDelegate, IDirtyPathCut * apDirtyPathCut=NULL) const;
+                             IGetDataDelegate * aDelegate, IDirtyPathCut * apDirtyPathCut = NULL) const;
 
-    WEAVE_ERROR RetrieveUpdatableDictionaryData(PropertyPathHandle aHandle, uint64_t aTagToWrite, nl::Weave::TLV::TLVWriter & aWriter,
-                                                IGetDataDelegate * aDelegate, PropertyPathHandle & aPropertyPathHandleOfDictItemToStartFrom) const;
+    WEAVE_ERROR RetrieveUpdatableDictionaryData(PropertyPathHandle aHandle, uint64_t aTagToWrite,
+                                                nl::Weave::TLV::TLVWriter & aWriter, IGetDataDelegate * aDelegate,
+                                                PropertyPathHandle & aPropertyPathHandleOfDictItemToStartFrom) const;
     /**********
      *
      * Schema Query Functions
@@ -473,7 +473,8 @@
      * @return     WEAVE_NO_ERROR in case of success; WEAVE_ERROR_NO_MEMORY if aTags is too small
      *             to store the full path.
      */
-    WEAVE_ERROR GetRelativePathTags(const PropertyPathHandle aCandidateHandle, uint64_t *aTags, const uint32_t aTagsSize, uint32_t &aNumTags) const;
+    WEAVE_ERROR GetRelativePathTags(const PropertyPathHandle aCandidateHandle, uint64_t * aTags, const uint32_t aTagsSize,
+                                    uint32_t & aNumTags) const;
     /**
      * Returns true if the passed in profileId matches that stored in the schema.
      *
@@ -544,7 +545,8 @@
      * aParseRes must be less than kContextTagMaxNum. If apEndptr is not NULL,
      * it stores the address of the first "/" in *apEndptr.
      */
-    WEAVE_ERROR ParseTagString(const char *apTagString, char **apEndptr, uint8_t& aParseRes) const;
+    WEAVE_ERROR ParseTagString(const char * apTagString, char ** apEndptr, uint8_t & aParseRes) const;
+
 public:
     const Schema mSchema;
 };
@@ -558,10 +560,9 @@
  *         It takes in a pointer to a schema that it then uses to help decipher incoming TLV data from a publisher and invoke the
  *         relevant data setter calls to pass the data up to subclasses.
  */
-class TraitDataSink : private TraitSchemaEngine::ISetDataDelegate
+class TraitDataSink : protected TraitSchemaEngine::ISetDataDelegate
 {
 public:
-
     TraitDataSink(const TraitSchemaEngine * aEngine);
     virtual ~TraitDataSink() { }
     const TraitSchemaEngine * GetSchemaEngine(void) const { return mSchemaEngine; }
@@ -585,7 +586,7 @@
      * @retval other           Encountered errors writing out the data.
      */
     WEAVE_ERROR StoreDataElement(PropertyPathHandle aHandle, TLV::TLVReader & aReader, uint8_t aFlags, OnChangeRejection aFunc,
-                                 void * aContext, TraitDataHandle aDatahandle=0);
+                                 void * aContext, TraitDataHandle aDatahandle = 0);
 
     /**
      * Retrieves the current version of the data that resides in this sink.
@@ -596,7 +597,7 @@
      */
     bool IsVersionValid(void) const { return mHasValidVersion; }
 
-    virtual bool IsVersionNewer(DataVersion &aVersion) { return aVersion != mVersion || false == mHasValidVersion; }
+    virtual bool IsVersionNewer(DataVersion & aVersion) { return aVersion != mVersion || false == mHasValidVersion; }
 
 #if WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
     /**
@@ -708,7 +709,7 @@
     virtual WEAVE_ERROR OnEvent(uint16_t aType, void * aInEventParam) { return WEAVE_NO_ERROR; }
 
 #if WEAVE_CONFIG_ENABLE_WDM_UPDATE
-    virtual bool IsUpdatableDataSink(void)  { return false; }
+    virtual bool IsUpdatableDataSink(void) { return false; }
 
     virtual WEAVE_ERROR SetSubscriptionClient(SubscriptionClient * apSubClient) { return WEAVE_NO_ERROR; };
     virtual WEAVE_ERROR SetUpdateEncoder(UpdateEncoder * apEncoder) { return WEAVE_NO_ERROR; };
@@ -743,7 +744,9 @@
      * subscriptionless notifications.
      */
     void SetAcceptsSubscriptionlessNotifications(const bool aAcceptsSublessNotifies)
-    { mAcceptsSubscriptionlessNotifications = aAcceptsSublessNotifies; }
+    {
+        mAcceptsSubscriptionlessNotifications = aAcceptsSublessNotifies;
+    }
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
 
     // Set current version of the data in this sink.
@@ -751,14 +754,13 @@
     void SetLastNotifyVersion(uint64_t version);
     uint64_t GetLastNotifyVersion(void) const { return mLastNotifyVersion; }
 
-
     const TraitSchemaEngine * mSchemaEngine;
 
 private:
     // Current version of the data in this sink.
     uint64_t mVersion;
     uint64_t mLastNotifyVersion;
-    void OnDataSinkEvent(DataSinkEventType aType, PropertyPathHandle aHandle) __OVERRIDE;
+    void OnSetDataEvent(SetDataEventType aType, PropertyPathHandle aHandle) __OVERRIDE;
     static OnChangeRejection sChangeRejectionCb;
     static void * sChangeRejectionContext;
     bool mHasValidVersion;
@@ -768,7 +770,7 @@
 #endif // WDM_ENABLE_SUBSCRIPTIONLESS_NOTIFICATION
 };
 
-#if    WEAVE_CONFIG_ENABLE_WDM_UPDATE
+#if WEAVE_CONFIG_ENABLE_WDM_UPDATE
 /*
  * @class  TraitUpdatableDataSink
  *
@@ -782,23 +784,33 @@
 public:
     TraitUpdatableDataSink(const TraitSchemaEngine * aEngine);
 
-    WEAVE_ERROR ReadData(TraitDataHandle aTraitDataHandle, PropertyPathHandle aHandle, uint64_t aTagToWrite, TLV::TLVWriter & aWriter, PropertyPathHandle & aPropertyPathHandleOfDictItemToStartFrom);
+    WEAVE_ERROR ReadData(TraitDataHandle aTraitDataHandle, PropertyPathHandle aHandle, uint64_t aTagToWrite,
+                         TLV::TLVWriter & aWriter, PropertyPathHandle & aPropertyPathHandleOfDictItemToStartFrom);
 
     virtual WEAVE_ERROR GetData(PropertyPathHandle aHandle, uint64_t aTagToWrite, nl::Weave::TLV::TLVWriter & aWriter,
                                 bool & aIsNull, bool & aIsPresent) __OVERRIDE;
 
-    WEAVE_ERROR SetUpdated(SubscriptionClient * apSubClient, PropertyPathHandle aPropertyHandle, bool aIsConditional=false);
+    WEAVE_ERROR SetUpdated(SubscriptionClient * apSubClient, PropertyPathHandle aPropertyHandle, bool aIsConditional = false);
 
     void Lock(SubscriptionClient * apSubClient);
     void Unlock(SubscriptionClient * apSubClient);
 
     virtual bool IsUpdatableDataSink(void) __OVERRIDE { return true; }
 
-    virtual WEAVE_ERROR SetSubscriptionClient(SubscriptionClient * apSubClient) __OVERRIDE { mpSubClient = apSubClient; return WEAVE_NO_ERROR; }
-    virtual WEAVE_ERROR SetUpdateEncoder(UpdateEncoder * apEncoder) __OVERRIDE { mpUpdateEncoder = apEncoder; return WEAVE_NO_ERROR; }
+    virtual WEAVE_ERROR SetSubscriptionClient(SubscriptionClient * apSubClient) __OVERRIDE
+    {
+        mpSubClient = apSubClient;
+        return WEAVE_NO_ERROR;
+    }
+    virtual WEAVE_ERROR SetUpdateEncoder(UpdateEncoder * apEncoder) __OVERRIDE
+    {
+        mpUpdateEncoder = apEncoder;
+        return WEAVE_NO_ERROR;
+    }
 
     virtual SubscriptionClient * GetSubscriptionClient() __OVERRIDE { return mpSubClient; }
     virtual UpdateEncoder * GetUpdateEncoder() __OVERRIDE { return mpUpdateEncoder; }
+
 private:
     friend class SubscriptionClient;
     friend class UpdateEncoder;
@@ -810,13 +822,16 @@
      * a version number that is lower than the current one. Please refer to the WDM
      * specification for more details.
      */
-    bool IsVersionNewer(DataVersion &aVersion) __OVERRIDE { return false == IsVersionValid() || aVersion > GetVersion() || aVersion  < GetLastNotifyVersion(); }
+    bool IsVersionNewer(DataVersion & aVersion) __OVERRIDE
+    {
+        return false == IsVersionValid() || aVersion > GetVersion() || aVersion < GetLastNotifyVersion();
+    }
     uint64_t GetUpdateRequiredVersion(void) const { return mUpdateRequiredVersion; }
     void ClearUpdateRequiredVersion(void) { SetUpdateRequiredVersion(0); }
-    void SetUpdateRequiredVersion(const uint64_t &aUpdateRequiredVersion);
+    void SetUpdateRequiredVersion(const uint64_t & aUpdateRequiredVersion);
 
     uint64_t GetUpdateStartVersion(void) const { return mUpdateStartVersion; }
-    void SetUpdateStartVersion (void);
+    void SetUpdateStartVersion(void);
     void ClearUpdateStartVersion(void) { mUpdateStartVersion = 0; }
 
     bool IsConditionalUpdate(void) { return mConditionalUpdate; }
@@ -832,7 +847,7 @@
     SubscriptionClient * mpSubClient;
     UpdateEncoder * mpUpdateEncoder;
 };
-#endif    // WEAVE_CONFIG_ENABLE_WDM_UPDATE
+#endif // WEAVE_CONFIG_ENABLE_WDM_UPDATE
 
 class Command;
 
@@ -856,6 +871,15 @@
 
     void SetDirty(PropertyPathHandle aPropertyHandle);
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    WEAVE_ERROR Unlock(bool aSkipVersionIncrement);
+
+    virtual bool IsUpdatableDataSource(void) { return false; }
+
+    // Check if version is equal to the internal trait version
+    bool IsVersionEqual(DataVersion & aVersion) { return aVersion == GetVersion(); }
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 #if TDM_ENABLE_PUBLISHER_DICTIONARY_SUPPORT
     void DeleteKey(PropertyPathHandle aPropertyHandle);
 #endif
@@ -869,9 +893,12 @@
     // API with all meta information housed within the Command
     // object.
     virtual void OnCustomCommand(Command * aCommand, const nl::Weave::WeaveMessageInfo * aMsgInfo,
-                                 nl::Weave::PacketBuffer * aPayload,
-                                 nl::Weave::TLV::TLVReader & aArgumentReader);
+                                 nl::Weave::PacketBuffer * aPayload, nl::Weave::TLV::TLVReader & aArgumentReader);
 
+    enum EventType
+    {
+        kEvent_DataSourceMax
+    };
     /*
      * Invoked either by the base class or by an external agent (like the subscription engine) to signal the occurrence of an event
      * (of type EventType). Sub-classes are expected to over-ride this if they desire to be made known of these events.
@@ -915,7 +942,6 @@
 
     // Increment current version of the data in this source.
     void IncrementVersion(void);
-
     // Controls whether mVersion is incremented automatically or not.
     bool mManagedVersion;
 
@@ -928,6 +954,151 @@
     bool mSetDirtyCalled;
 };
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+/*
+ * @class  TraitUpdatableDataSource
+ *
+ * @brief  Base abstract class that represents a particular instance of a trait on a specific resource (publisher).
+ * Application developers are expected to subclass this to make a concrete source that apply data received from client
+ *
+ */
+class TraitUpdatableDataSource : public TraitDataSource, protected TraitSchemaEngine::ISetDataDelegate
+{
+public:
+    TraitUpdatableDataSource(const TraitSchemaEngine * aEngine);
+
+    typedef WEAVE_ERROR (*OnChangeRejection)(uint16_t aRejectionStatusCode, uint64_t aVersion, void * aContext);
+
+    /**
+     * Convenience function for data sinks to handle unknown leaf handles with
+     * a system level tolerance for mismatched schema as defined by
+     * TDM_DISABLE_STRICT_SCHEMA_COMPILANCE.
+     */
+    WEAVE_ERROR HandleUnknownLeafHandle(void)
+    {
+#if TDM_DISABLE_STRICT_SCHEMA_COMPLIANCE
+        return WEAVE_NO_ERROR;
+#else
+        return WEAVE_ERROR_TLV_TAG_NOT_FOUND;
+#endif
+    }
+
+    enum EventType
+    {
+        kEventChangeFirst = kEvent_DataSourceMax,
+
+        /* Signals the beginning of a change record which in certain scenarios can span multiple data elements over multiple
+         * update requests (the latter only a possibility if the data being transmitted is unable to fit within a single packet)
+         */
+        kEventChangeBegin,
+
+        /* Start of a data element */
+        kEventDataElementBegin,
+
+        /* End of a data element */
+        kEventDataElementEnd,
+
+        /* End of a change record */
+        kEventChangeEnd,
+
+        /* Start of replacement of an entire dictionary */
+        kEventDictionaryReplaceBegin,
+
+        /* End of replacement of an entire dictionary */
+        kEventDictionaryReplaceEnd,
+
+        /* Start of modification or addition of a dictionary item */
+        kEventDictionaryItemModifyBegin,
+
+        /* End of modification or addition of a dictionary item */
+        kEventDictionaryItemModifyEnd,
+
+        /* Deletion of a dictionary item */
+        kEventDictionaryItemDelete,
+
+        /* Signals the start of the processing of a update request packet
+         */
+        kEventUpdateRequestBegin,
+
+        /* Signals the end of the processing of a update request packet
+         */
+        kEventUpdateRequestEnd,
+
+        /* Signals the termination of a subscription either due to an error, or the subscription was cancelled */
+        kEventSubscriptionTerminated,
+
+        kEvent_UpdatableDataSourceMax
+    };
+
+    union InEventParam
+    {
+        struct
+        {
+            PropertyPathHandle mTargetHandle;
+        } mDictionaryReplaceBegin;
+
+        struct
+        {
+            PropertyPathHandle mTargetHandle;
+        } mDictionaryReplaceEnd;
+
+        struct
+        {
+            PropertyPathHandle mTargetHandle;
+        } mDictionaryItemModifyBegin;
+
+        struct
+        {
+            PropertyPathHandle mTargetHandle;
+        } mDictionaryItemModifyEnd;
+
+        struct
+        {
+            PropertyPathHandle mTargetHandle;
+        } mDictionaryItemDelete;
+    };
+
+    /**
+     * Given a reader that points to a data element conformant to a schema bound to this object, this method processes that data and
+     * invokes the relevant SetLeafData call below for all leaf items in the buffer.
+     *
+     * A change rejection function can be passed in as well that will be invoked if the updatable source chooses to reject this data
+     * for any reason.
+     *
+     * @retval #WEAVE_NO_ERROR On success.
+     * @retval other           Encountered errors writing out the data.
+     */
+    WEAVE_ERROR StoreDataElement(PropertyPathHandle aHandle, TLV::TLVReader & aReader, uint8_t aFlags, OnChangeRejection aFunc,
+                                 void * aContext);
+    virtual bool IsUpdatableDataSource(void) __OVERRIDE { return true; }
+
+protected: // ISetDataDelegate
+    virtual WEAVE_ERROR SetLeafData(PropertyPathHandle aLeafHandle, nl::Weave::TLV::TLVReader & aReader) __OVERRIDE = 0;
+
+    /*
+     * Defaults to calling SetLeafData if aHandle is a leaf. DataSinks
+     * can optionally implement this if they need to support nullable,
+     * ephemeral, or optional properties.
+     *
+     * TODO: make this the defacto API, moving all the logic from
+     * SetLeafData into this function.
+     */
+    virtual WEAVE_ERROR SetData(PropertyPathHandle aHandle, nl::Weave::TLV::TLVReader & aReader, bool aIsNull) __OVERRIDE;
+
+    /* Subclass can invoke this if they desire to reject a particular data change */
+    void RejectChange(uint16_t aRejectionStatusCode);
+
+private:
+    friend class SubscriptionEngine;
+
+    void OnSetDataEvent(SetDataEventType aType, PropertyPathHandle aHandle) __OVERRIDE;
+
+private:
+    static OnChangeRejection sChangeRejectionCb;
+    static void * sChangeRejectionContext;
+};
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 }; // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
 }; // namespace Profiles
 }; // namespace Weave
diff --git a/src/lib/profiles/status-report/StatusReportProfile.cpp b/src/lib/profiles/status-report/StatusReportProfile.cpp
index 085de6c..bcf805c 100644
--- a/src/lib/profiles/status-report/StatusReportProfile.cpp
+++ b/src/lib/profiles/status-report/StatusReportProfile.cpp
@@ -81,7 +81,7 @@
     return WEAVE_NO_ERROR;
 }
 
-WEAVE_ERROR StatusReport::pack(PacketBuffer *aBuffer)
+WEAVE_ERROR StatusReport::pack(PacketBuffer *aBuffer, uint32_t maxLen)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     MessageIterator i(aBuffer);
@@ -129,7 +129,7 @@
 
     else
     {
-        err = mAdditionalInfo.pack(i);
+        err = mAdditionalInfo.pack(i, maxLen - 6);
     }
 
 exit:
diff --git a/src/lib/profiles/status-report/StatusReportProfile.h b/src/lib/profiles/status-report/StatusReportProfile.h
index e3cc58f..4f5affb 100644
--- a/src/lib/profiles/status-report/StatusReportProfile.h
+++ b/src/lib/profiles/status-report/StatusReportProfile.h
@@ -73,7 +73,7 @@
 
         WEAVE_ERROR init(WEAVE_ERROR aError);
 
-        WEAVE_ERROR pack(PacketBuffer *aBuffer);
+        WEAVE_ERROR pack(PacketBuffer *aBuffer, uint32_t maxLen = 0xFFFFFFFFUL);
         uint16_t packedLength(void);
         static WEAVE_ERROR parse(PacketBuffer *aBuffer, StatusReport &aDestination);
 
diff --git a/src/test-apps/Makefile.am b/src/test-apps/Makefile.am
index 9d35c48..801e077 100644
--- a/src/test-apps/Makefile.am
+++ b/src/test-apps/Makefile.am
@@ -1035,6 +1035,8 @@
     happy/tests/standalone/wdmNext/test_weave_wdm_next_update_01.py       \
     happy/tests/standalone/wdmNext/test_weave_wdm_next_update_02.py       \
     happy/tests/standalone/wdmNext/test_weave_wdm_next_update_03.py       \
+    happy/tests/standalone/wdmNext/test_weave_wdm_next_update_04.py       \
+    happy/tests/standalone/wdmNext/test_weave_wdm_next_update_05.py       \
     $(NULL)
 
 endif # WEAVE_RUN_HAPPY_WDM
@@ -1411,6 +1413,7 @@
                                            TestWdmSubscriptionlessNotificationReceiver.cpp		\
                                            schema/nest/test/trait/TestATrait.cpp			\
                                            schema/nest/test/trait/TestBTrait.cpp			\
+                                           schema/nest/test/trait/TestCTrait.cpp            \
                                            schema/nest/test/trait/TestETrait.cpp			\
                                            schema/nest/test/trait/TestCommon.cpp \
                                            schema/weave/trait/locale/LocaleSettingsTrait.cpp		\
@@ -1441,6 +1444,7 @@
                                            MockEvents.cpp						\
                                            schema/nest/test/trait/TestATrait.cpp			\
                                            schema/nest/test/trait/TestBTrait.cpp			\
+                                           schema/nest/test/trait/TestCTrait.cpp			\
                                            schema/nest/test/trait/TestETrait.cpp			\
                                            schema/nest/test/trait/TestCommon.cpp                        \
                                            schema/weave/trait/locale/LocaleSettingsTrait.cpp		\
@@ -1474,6 +1478,7 @@
                                            MockSourceTraits.cpp                                     \
                                            schema/nest/test/trait/TestATrait.cpp                    \
                                            schema/nest/test/trait/TestBTrait.cpp                    \
+                                           schema/nest/test/trait/TestCTrait.cpp                    \
                                            schema/nest/test/trait/TestETrait.cpp                    \
                                            schema/nest/test/trait/TestCommon.cpp \
                                            schema/weave/trait/locale/LocaleSettingsTrait.cpp        \
diff --git a/src/test-apps/MockSourceTraits.cpp b/src/test-apps/MockSourceTraits.cpp
index 3a59d9b..9c88e35 100644
--- a/src/test-apps/MockSourceTraits.cpp
+++ b/src/test-apps/MockSourceTraits.cpp
@@ -72,11 +72,16 @@
     return strlen(src);
 }
 
-LocaleSettingsTraitDataSource::LocaleSettingsTraitDataSource()
-    : TraitDataSource(&LocaleSettingsTrait::TraitSchema)
+LocaleSettingsTraitDataSource::LocaleSettingsTraitDataSource():
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+     TraitUpdatableDataSource(&LocaleSettingsTrait::TraitSchema)
+#else
+     TraitDataSource(&LocaleSettingsTrait::TraitSchema)
+#endif
 {
     SetVersion(300);
     memset(mLocale, 0, sizeof(mLocale));
+    MOCK_strlcpy(mLocale, "en-US", sizeof(mLocale));
 }
 
 void LocaleSettingsTraitDataSource::Mutate()
@@ -94,6 +99,37 @@
     Unlock();
 }
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+WEAVE_ERROR
+LocaleSettingsTraitDataSource::SetLeafData(PropertyPathHandle aLeafHandle, TLVReader &aReader)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    switch (aLeafHandle) {
+        case LocaleSettingsTrait::kPropertyHandle_active_locale:
+            char next_locale[24];
+            err = aReader.GetString(next_locale, MAX_LOCALE_SIZE);
+            SuccessOrExit(err);
+            if (strncmp(next_locale, mLocale, MAX_LOCALE_SIZE) != 0)
+            {
+                WeaveLogDetail(DataManagement, "<<  active_locale is changed from \"%s\" to \"%s\"", mLocale, next_locale);
+                memcpy(mLocale, next_locale, MAX_LOCALE_SIZE);
+            }
+
+            WeaveLogDetail(DataManagement, "<<  active_locale = \"%s\"", mLocale);
+            break;
+
+        default:
+            WeaveLogDetail(DataManagement, "<<  UNKNOWN!");
+            err = WEAVE_ERROR_TLV_TAG_NOT_FOUND;
+    }
+
+exit:
+    return err;
+}
+
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 WEAVE_ERROR
 LocaleSettingsTraitDataSource::GetLeafData(PropertyPathHandle aLeafHandle, uint64_t aTagToWrite, TLVWriter &aWriter)
 {
@@ -119,14 +155,17 @@
 }
 
 LocaleCapabilitiesTraitDataSource::LocaleCapabilitiesTraitDataSource()
-    : TraitDataSource(&LocaleCapabilitiesTrait::TraitSchema)
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    :TraitUpdatableDataSource(&LocaleCapabilitiesTrait::TraitSchema)
+#else
+    :TraitDataSource(&LocaleCapabilitiesTrait::TraitSchema)
+#endif
 {
     SetVersion(400);
 
-    mNumLocales = 3;
-    mLocales[0] = "pl-PL";
-    mLocales[1] = "ja-JP";
-    mLocales[2] = "fr-FR";
+    memcpy(mLocales[0], "pl-PL", MAX_LOCALE_SIZE);
+    memcpy(mLocales[1], "ja-JP", MAX_LOCALE_SIZE);
+    memcpy(mLocales[2], "fr-FR", MAX_LOCALE_SIZE);
 }
 
 void LocaleCapabilitiesTraitDataSource::Mutate()
@@ -136,20 +175,20 @@
     switch (GetVersion() % 3) {
         case 0:
             mNumLocales = 2;
-            mLocales[0] = "en-US";
-            mLocales[1] = "zh-TW";
+            memcpy(mLocales[0], "en-US", MAX_LOCALE_SIZE);
+            memcpy(mLocales[1], "zh-TW", MAX_LOCALE_SIZE);
             break;
 
         case 1:
             mNumLocales = 1;
-            mLocales[0] = "zh-CN";
+            memcpy(mLocales[0], "zh-CN", MAX_LOCALE_SIZE);
             break;
 
         case 2:
             mNumLocales = 3;
-            mLocales[0] = "ja-JP";
-            mLocales[1] = "pl-PL";
-            mLocales[2] = "zh-CN";
+            memcpy(mLocales[0], "ja-JP", MAX_LOCALE_SIZE);
+            memcpy(mLocales[1], "pl-PL", MAX_LOCALE_SIZE);
+            memcpy(mLocales[2], "zh-CN", MAX_LOCALE_SIZE);
             break;
     }
 
@@ -158,6 +197,65 @@
     Unlock();
 }
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+WEAVE_ERROR
+LocaleCapabilitiesTraitDataSource::SetLeafData(PropertyPathHandle aLeafHandle, TLVReader &aReader)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    char next_locale[kMaxNumOfCharsPerLocale];
+
+    if (LocaleCapabilitiesTrait::kPropertyHandle_available_locales == aLeafHandle)
+    {
+        nl::Weave::TLV::TLVType OuterContainerType;
+
+        // clear all locales
+        mNumLocales = 0;
+
+        VerifyOrExit(aReader.GetType() == nl::Weave::TLV::kTLVType_Array, err = WEAVE_ERROR_WRONG_TLV_TYPE);
+
+        err = aReader.EnterContainer(OuterContainerType);
+        SuccessOrExit(err);
+
+        while (WEAVE_NO_ERROR == (err = aReader.Next()))
+        {
+            VerifyOrExit(nl::Weave::TLV::kTLVType_UTF8String == aReader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
+            VerifyOrExit(nl::Weave::TLV::AnonymousTag == aReader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
+
+            err = aReader.GetString(next_locale, kMaxNumOfCharsPerLocale);
+            SuccessOrExit(err);
+            if (strncmp(next_locale, mLocales[mNumLocales], MAX_LOCALE_SIZE) != 0)
+            {
+                 WeaveLogDetail(DataManagement,  "<<  locale[%u]  is changed from [%s] to [%s]", mNumLocales, mLocales[mNumLocales], next_locale);
+                 memcpy(mLocales[mNumLocales], next_locale, MAX_LOCALE_SIZE);
+            }
+
+            WeaveLogDetail(DataManagement, "<<  locale[%u] = [%s]", mNumLocales, mLocales[mNumLocales]);
+
+            ++mNumLocales;
+
+            if (kMaxNumOfLocals == mNumLocales)
+            {
+                WeaveLogDetail(DataManagement, "Cannot handle more than %d locales, skip", kMaxNumOfLocals);
+                break;
+            }
+        }
+
+        // Note that ExitContainer internally skip all unread elements till the end of current container
+        err = aReader.ExitContainer(OuterContainerType);
+        SuccessOrExit(err);
+    }
+    else
+    {
+        WeaveLogDetail(DataManagement, "<<  UNKNOWN!");
+        ExitNow(err = WEAVE_ERROR_INVALID_TLV_TAG);
+    }
+
+exit:
+    return err;
+}
+
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 WEAVE_ERROR
 LocaleCapabilitiesTraitDataSource::GetLeafData(PropertyPathHandle aLeafHandle, uint64_t aTagToWrite, TLVWriter &aWriter)
 {
@@ -245,9 +343,13 @@
     return err;
 }
 
-TestATraitDataSource::TestATraitDataSource()
-    : TraitDataSource(&TestATrait::TraitSchema),
-      mActiveCommand(NULL)
+TestATraitDataSource::TestATraitDataSource():
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+     TraitUpdatableDataSource(&TestATrait::TraitSchema),
+#else
+     TraitDataSource(&TestATrait::TraitSchema),
+#endif
+     mActiveCommand(NULL)
 {
     uint8_t *tmp;
     SetVersion(100);
@@ -748,6 +850,251 @@
     }
 }
 
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+WEAVE_ERROR
+TestATraitDataSource::SetLeafData(PropertyPathHandle aLeafHandle, TLVReader &aReader)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    switch (GetPropertySchemaHandle(aLeafHandle)) {
+        case TestATrait::kPropertyHandle_TaA:
+            err = aReader.Get(taa);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_a = %u", taa);
+            break;
+
+        case TestATrait::kPropertyHandle_TaB:
+            err = aReader.Get(tab);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_b = %u", tab);
+            break;
+
+        case TestATrait::kPropertyHandle_TaC:
+            uint32_t next_tac;
+            err = aReader.Get(next_tac);
+            SuccessOrExit(err);
+            if (next_tac != tac)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_c is changed from %u to %u", tac, next_tac);
+                tac = next_tac;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  ta_c = %u", tac);
+            break;
+
+        case TestATrait::kPropertyHandle_TaD_SaA:
+            uint32_t next_tad_saa;
+            err = aReader.Get(next_tad_saa);
+            SuccessOrExit(err);
+            if (next_tad_saa != tad.saA)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_d.sa_a is changed from %u to %u", tad.saA, next_tad_saa);
+                tad.saA = next_tad_saa;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  ta_d.sa_a = %u", tad.saA);
+            break;
+
+        case TestATrait::kPropertyHandle_TaD_SaB:
+            bool next_tad_sab;
+            err = aReader.Get(next_tad_sab);
+            SuccessOrExit(err);
+            if (next_tad_sab != tad.saB)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_d.sa_b is changed from %u to %u", tad.saB, next_tad_sab);
+                tad.saB = next_tad_sab;
+            }
+
+            WeaveLogDetail(DataManagement, "<<  ta_d.sa_b = %u", tad.saB);
+            break;
+
+        case TestATrait::kPropertyHandle_TaE:
+        {
+            TLVType outerType;
+            uint32_t i = 0;
+
+            err = aReader.EnterContainer(outerType);
+            SuccessOrExit(err);
+
+            while (((err = aReader.Next()) == WEAVE_NO_ERROR) && (i < (sizeof(tae) / sizeof(tae[0])))) {
+                uint32_t next_tae;
+                err = aReader.Get(next_tae);
+                SuccessOrExit(err);
+                if (tae[i] != next_tae)
+                {
+                    WeaveLogDetail(DataManagement, "<<  ta_e[%u] is changed from %u to %u", i, tae[i], next_tae);
+                    tae[i] = next_tae;
+                }
+
+                WeaveLogDetail(DataManagement, "<<  ta_e[%u] = %u", i, tae[i]);
+                i++;
+            }
+
+            err = aReader.ExitContainer(outerType);
+            break;
+        }
+
+        case TestATrait::kPropertyHandle_TaG:
+        {
+            if (aReader.GetType() == kTLVType_UTF8String)
+            {
+                err = aReader.GetString(tag_string, sizeof(tag_string));
+                SuccessOrExit(err);
+
+                tag_use_ref = false;
+
+                WeaveLogDetail(DataManagement, "<<  ta_g string = %s", tag_string);
+            }
+            else
+            {
+                err = aReader.Get(tag_ref);
+                SuccessOrExit(err);
+
+                tag_use_ref = true;
+
+                WeaveLogDetail(DataManagement, "<<  ta_g ref = %u", tag_ref);
+            }
+        }
+            break;
+
+        case TestATrait::kPropertyHandle_TaK:
+            err = aReader.GetBytes(&tak[0], sizeof(tak));
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_k %d bytes", sizeof(tak));
+            break;
+
+        case TestATrait::kPropertyHandle_TaL:
+            err = aReader.Get(tal);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_l = %x", tal);
+            break;
+
+        case TestATrait::kPropertyHandle_TaM:
+            err = aReader.Get(tam_resourceid);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_m = %" PRIx64 , tam_resourceid);
+            break;
+
+        case TestATrait::kPropertyHandle_TaN:
+            err = aReader.GetBytes(&tan[0], sizeof(tan));
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_n %d bytes", sizeof(tan));
+            DumpMemory(&tan[0], sizeof(tan), "WEAVE:DMG: <<  ta_n ", 16);
+            break;
+
+        case TestATrait::kPropertyHandle_TaO:
+            err = aReader.Get(tao);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_o = %d", tao);
+            break;
+
+        case TestATrait::kPropertyHandle_TaP:
+            int64_t next_tap;
+            err = aReader.Get(next_tap);
+            SuccessOrExit(err);
+
+            if (next_tap != tap)
+            {
+                WeaveLogDetail(DataManagement, "<<  ta_p is changed from %d to %d", tap, next_tap);
+                tap = next_tap;
+            }
+            WeaveLogDetail(DataManagement, "<<  ta_p = %d", tap);
+            break;
+
+        case TestATrait::kPropertyHandle_TaQ:
+            err = aReader.Get(taq);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_q %" PRId64 , taq);
+            break;
+
+        case TestATrait::kPropertyHandle_TaR:
+            err = aReader.Get(tar);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_r %u", tar);
+            break;
+
+        case TestATrait::kPropertyHandle_TaS:
+            err = aReader.Get(tas);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_s %u", tas);
+            break;
+
+        case TestATrait::kPropertyHandle_TaT:
+            err = aReader.Get(tat);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_t %u", tat);
+            break;
+
+        case TestATrait::kPropertyHandle_TaU:
+            err = aReader.Get(tau);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_u %d", tau);
+            break;
+
+        case TestATrait::kPropertyHandle_TaV:
+            err = aReader.Get(tav);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_v %u", tav);
+            break;
+
+        case TestATrait::kPropertyHandle_TaW:
+            err = aReader.GetString(&taw[0], sizeof(taw));
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_w %s", taw);
+            break;
+
+        case TestATrait::kPropertyHandle_TaX:
+            err = aReader.Get(tax);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  ta_x %d", tax);
+            break;
+
+        case TestATrait::kPropertyHandle_TaI_Value:
+            err = aReader.Get(tai_stageditem);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  tai[%u] = %u", GetPropertyDictionaryKey(aLeafHandle), tai_stageditem);
+            break;
+
+        case TestATrait::kPropertyHandle_TaJ_Value_SaA:
+            err = aReader.Get(taj_stageditem.saA);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  taj[%u].sa_a = %u", GetPropertyDictionaryKey(aLeafHandle), taj_stageditem.saA);
+            break;
+
+        case TestATrait::kPropertyHandle_TaJ_Value_SaB:
+            err = aReader.Get(taj_stageditem.saB);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  taj[%u].sa_b = %u", GetPropertyDictionaryKey(aLeafHandle), taj_stageditem.saB);
+            break;
+
+        default:
+            WeaveLogDetail(DataManagement, "<<  UNKNOWN!");
+    }
+
+    exit:
+    return err;
+}
+
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
 WEAVE_ERROR TestATraitDataSource::GetData(PropertyPathHandle aHandle,
                                           uint64_t aTagToWrite,
                                           TLVWriter &aWriter,
@@ -1992,3 +2339,147 @@
 
     return err;
 }
+
+TestCTraitDataSource::TestCTraitDataSource():
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+        TraitUpdatableDataSource(&TestCTrait::TraitSchema)
+#else
+        TraitDataSource(&TestCTrait::TraitSchema)
+#endif
+{
+    SetVersion(300);
+    taa = true;
+    tab = TestCTrait::ENUM_C_VALUE_1;
+    tac.scA= 3;
+    tac.scB = true;
+    tad = 4;
+}
+
+void TestCTraitDataSource::Mutate()
+{
+    Lock();
+
+    if ((GetVersion() % 2) == 0) {
+        SetDirty(TestCTrait::kPropertyHandle_TcA);
+        taa = !taa;
+    }
+    else
+    {
+        SetDirty(TestCTrait::kPropertyHandle_TcC_ScA);
+        SetDirty(TestCTrait::kPropertyHandle_TcC_ScB);
+        tac.scA ++;
+        tac.scB = !tac.scB;
+    }
+
+    Unlock();
+}
+
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+void TestCTraitDataSource::TLVPrettyPrinter(const char *aFormat, ...)
+{
+    va_list args;
+
+    va_start(args, aFormat);
+
+    vprintf(aFormat, args);
+
+    va_end(args);
+}
+
+WEAVE_ERROR
+TestCTraitDataSource::SetLeafData(PropertyPathHandle aLeafHandle, TLVReader &aReader)
+{
+
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    switch (aLeafHandle) {
+        case TestCTrait::kPropertyHandle_TcA:
+            err = aReader.Get(taa);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<< taa = %s", taa ? "true" : "false");
+            break;
+        case TestCTrait::kPropertyHandle_TcB:
+            err = aReader.Get(tab);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  tab %d", tab);
+            break;
+        case TestCTrait::kPropertyHandle_TcC_ScA:
+            err = aReader.Get(tac.scA);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  tac.scA %u", tac.scA);
+            break;
+        case TestCTrait::kPropertyHandle_TcC_ScB:
+            err = aReader.Get(tac.scB);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  tac.scB = %s",  tac.scB ? "true" : "false");
+            break;
+        case TestCTrait::kPropertyHandle_TcD:
+            err = aReader.Get(tad);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, "<<  tad %u", tad);
+            break;
+
+        default:
+            WeaveLogDetail(DataManagement, "<<  UNKNOWN!");
+            err = WEAVE_ERROR_TLV_TAG_NOT_FOUND;
+    }
+
+exit:
+    return err;
+}
+
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
+WEAVE_ERROR
+TestCTraitDataSource::GetLeafData(PropertyPathHandle aLeafHandle, uint64_t aTagToWrite, TLVWriter &aWriter)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    switch (aLeafHandle) {
+        case TestCTrait::kPropertyHandle_TcA:
+            err = aWriter.PutBoolean(aTagToWrite, taa);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, ">>  taa = %s", taa ? "true" : "false");
+            break;
+        case TestCTrait::kPropertyHandle_TcB:
+            err = aWriter.Put(aTagToWrite, tab);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, ">>  tab = %d", tab);
+            break;
+
+        case TestCTrait::kPropertyHandle_TcC_ScA:
+            err = aWriter.Put(aTagToWrite, tac.scA);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, ">>  tac.scA = %u", tac.scA);
+            break;
+
+        case TestCTrait::kPropertyHandle_TcC_ScB:
+            err = aWriter.PutBoolean(aTagToWrite, taa);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, ">>  tac.scB = %s",  tac.scB ? "true" : "false");
+            break;
+        case TestCTrait::kPropertyHandle_TcD:
+            err = aWriter.Put(aTagToWrite, tad);
+            SuccessOrExit(err);
+
+            WeaveLogDetail(DataManagement, ">>  tad = %u", tad);
+            break;
+
+        default:
+            WeaveLogDetail(DataManagement, ">>  UNKNOWN!");
+            ExitNow(err = WEAVE_ERROR_TLV_TAG_NOT_FOUND);
+    }
+
+exit:
+    WeaveLogFunctError(err);
+
+    return err;
+}
diff --git a/src/test-apps/MockSourceTraits.h b/src/test-apps/MockSourceTraits.h
index d1c7af4..9e802a1 100644
--- a/src/test-apps/MockSourceTraits.h
+++ b/src/test-apps/MockSourceTraits.h
@@ -34,37 +34,58 @@
 #include <weave/trait/locale/LocaleCapabilitiesTrait.h>
 #include <nest/test/trait/TestATrait.h>
 #include <nest/test/trait/TestBTrait.h>
+#include <nest/test/trait/TestCTrait.h>
+#include <nest/test/trait/TestDTrait.h>
 #include <nest/test/trait/TestCommon.h>
 #include "TestGroupKeyStore.h"
 #include <map>
 
-class LocaleSettingsTraitDataSource : public nl::Weave::Profiles::DataManagement::TraitDataSource
+#define MAX_LOCALE_SIZE sizeof(char) * 24
+
+class LocaleSettingsTraitDataSource :
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+        public nl::Weave::Profiles::DataManagement::TraitUpdatableDataSource
+#else
+        public nl::Weave::Profiles::DataManagement::TraitDataSource
+#endif
 {
 public:
     LocaleSettingsTraitDataSource();
     void Mutate();
 
 private:
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    WEAVE_ERROR SetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, nl::Weave::TLV::TLVReader &aReader) __OVERRIDE;
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
     WEAVE_ERROR GetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, uint64_t aTagToWrite, nl::Weave::TLV::TLVWriter &aWriter) __OVERRIDE;
 
     char mLocale[24];
 };
 
-class LocaleCapabilitiesTraitDataSource : public nl::Weave::Profiles::DataManagement::TraitDataSource
+class LocaleCapabilitiesTraitDataSource :
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+        public nl::Weave::Profiles::DataManagement::TraitUpdatableDataSource
+#else
+        public nl::Weave::Profiles::DataManagement::TraitDataSource
+#endif
 {
 public:
     LocaleCapabilitiesTraitDataSource();
     void Mutate();
 
 private:
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    WEAVE_ERROR SetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, nl::Weave::TLV::TLVReader &aReader) __OVERRIDE;
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
     WEAVE_ERROR GetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, uint64_t aTagToWrite, nl::Weave::TLV::TLVWriter &aWriter) __OVERRIDE;
 
     enum {
+        kMaxNumOfCharsPerLocale = 24,
         kMaxNumOfLocals = 10,
     };
 
     uint8_t mNumLocales;
-    const char * mLocales[kMaxNumOfLocals];
+    char mLocales[kMaxNumOfLocals][kMaxNumOfCharsPerLocale];
 };
 
 class BoltLockSettingTraitDataSource : public nl::Weave::Profiles::DataManagement::TraitDataSource
@@ -80,7 +101,12 @@
     uint32_t mAutoRelockDuration;
 };
 
-class TestATraitDataSource : public nl::Weave::Profiles::DataManagement::TraitDataSource
+class TestATraitDataSource :
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+        public nl::Weave::Profiles::DataManagement::TraitUpdatableDataSource
+#else
+        public nl::Weave::Profiles::DataManagement::TraitDataSource
+#endif
 {
 public:
     TestATraitDataSource();
@@ -89,6 +115,10 @@
     uint32_t mTraitTestSet;
 
 private:
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    WEAVE_ERROR SetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, nl::Weave::TLV::TLVReader &aReader) __OVERRIDE;
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
     void SetNullifiedPath(nl::Weave::Profiles::DataManagement::PropertyPathHandle aHandle, bool isNull);
 
     WEAVE_ERROR GetData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aHandle, uint64_t aTagToWrite, nl::Weave::TLV::TLVWriter &aWriter, bool &aIsNull, bool &aIsPresent) __OVERRIDE;
@@ -126,11 +156,12 @@
     uint32_t tae[10];
 
     // weave.common.StringRef is implemented as a union
-    const char *tag_string = "stringreftest";
+    char *tag_string = "stringreftest";
     uint16_t tag_ref;
     bool tag_use_ref;
-
+    uint32_t tai_stageditem;
     std::map<uint16_t, uint32_t> tai_map;
+    Schema::Nest::Test::Trait::TestATrait::StructA taj_stageditem;
     std::map<uint16_t, Schema::Nest::Test::Trait::TestATrait::StructA> taj_map;
 
     // byte array
@@ -155,7 +186,7 @@
     uint32_t tat;
     int32_t tau;
     bool tav;
-    const char *taw = "boxedstring";
+    char *taw = "boxedstring";
     // boxed float
     int16_t tax;
 
@@ -241,4 +272,27 @@
     nl::Weave::Profiles::Security::AppKeys::WeaveGroupKey GroupMasterKeys[WEAVE_CONFIG_MAX_APPLICATION_GROUPS];
 };
 
+class TestCTraitDataSource :
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+        public nl::Weave::Profiles::DataManagement::TraitUpdatableDataSource
+#else
+        public nl::Weave::Profiles::DataManagement::TraitDataSource
+#endif
+{
+public:
+    TestCTraitDataSource();
+    void Mutate();
+    static void TLVPrettyPrinter(const char *aFormat, ...);
+private:
+#if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+    WEAVE_ERROR SetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, nl::Weave::TLV::TLVReader &aReader) __OVERRIDE;
+#endif // WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
+
+    WEAVE_ERROR GetLeafData(nl::Weave::Profiles::DataManagement::PropertyPathHandle aLeafHandle, uint64_t aTagToWrite, nl::Weave::TLV::TLVWriter &aWriter) __OVERRIDE;
+    bool taa;
+    int32_t tab;
+    Schema::Nest::Test::Trait::TestCTrait::StructC tac;
+    uint32_t tad;
+};
+
 #endif // MOCK_TRAIT_SOURCES_H_
diff --git a/src/test-apps/MockWdmSubscriptionInitiator.cpp b/src/test-apps/MockWdmSubscriptionInitiator.cpp
index 51b99d6..77d311c 100644
--- a/src/test-apps/MockWdmSubscriptionInitiator.cpp
+++ b/src/test-apps/MockWdmSubscriptionInitiator.cpp
@@ -1142,7 +1142,7 @@
         break;
 #if WEAVE_CONFIG_ENABLE_WDM_UPDATE
     case SubscriptionClient::kEvent_OnUpdateComplete:
-        if ((aInParam.mUpdateComplete.mReason == WEAVE_NO_ERROR) && (nl::Weave::Profiles::Common::kStatus_Success == aInParam.mUpdateComplete.mStatusCode))
+        if ((aInParam.mUpdateComplete.mReason == WEAVE_NO_ERROR) && (nl::Weave::Profiles::kWeaveProfile_Common == aInParam.mUpdateComplete.mStatusProfileId) && (nl::Weave::Profiles::Common::kStatus_Success == aInParam.mUpdateComplete.mStatusCode))
         {
             WeaveLogDetail(DataManagement, "Update: path result: success");
         }
@@ -1156,8 +1156,6 @@
 
             if (initiator->mUpdateDiscardOnError)
             {
-                TraitDataSink *sink = NULL;
-                initiator->mSinkCatalog.Locate(aInParam.mUpdateComplete.mTraitDataHandle, &sink);
                 initiator->mSubscriptionClient->DiscardUpdates();
             }
         }
diff --git a/src/test-apps/MockWdmSubscriptionResponder.cpp b/src/test-apps/MockWdmSubscriptionResponder.cpp
index 469681c..e6be727 100644
--- a/src/test-apps/MockWdmSubscriptionResponder.cpp
+++ b/src/test-apps/MockWdmSubscriptionResponder.cpp
@@ -152,16 +152,18 @@
     // publisher side
     uint32_t mTimeBetweenLivenessCheckSec;
     SingleResourceSourceTraitCatalog mSourceCatalog;
-    SingleResourceSourceTraitCatalog::CatalogItem mSourceCatalogStore[6];
+    SingleResourceSourceTraitCatalog::CatalogItem mSourceCatalogStore[10];
 
     // source traits
     LocaleSettingsTraitDataSource mLocaleSettingsDataSource;
+    LocaleCapabilitiesTraitDataSource mLocaleCapabilitiesDataSource;
     TestATraitDataSource mTestADataSource0;
     TestATraitDataSource mTestADataSource1;
     TestBTraitDataSource mTestBDataSource;
     TestBLargeTraitDataSource mTestBLargeDataSource;
     BoltLockSettingTraitDataSource mBoltLockSettingDataSource;
     ApplicationKeysTraitDataSource mApplicationKeysTraitDataSource;
+    TestCTraitDataSource mTestCDataSource;
 
     static void EngineEventCallback (void * const aAppState, SubscriptionEngine::EventID aEvent,
         const SubscriptionEngine::InEventParam & aInParam, SubscriptionEngine::OutEventParam & aOutParam);
@@ -193,6 +195,8 @@
         kLocaleSettingsTraitSourceIndex,
         kBoltLockSettingTraitSourceIndex,
         kApplicationKeysTraitSourceIndex,
+        kTestCTraitSourceIndex,
+        kLocaleCapabilitiesTraitSourceIndex,
 
         kNumTraitHandles,
     };
@@ -293,15 +297,6 @@
         const nl::Weave::WeaveMessageInfo *aMsgInfo, uint32_t aProfileId,
         uint8_t aMsgType, PacketBuffer *aPayload);
     static void HandleCustomCommandTimeout(nl::Weave::System::Layer* aSystemLayer, void *aAppState, ::nl::Weave::System::Error aErr);
-    static void IncomingUpdateRequest(nl::Weave::ExchangeContext *ec, const nl::Weave::IPPacketInfo *pktInfo,
-            const nl::Weave::WeaveMessageInfo *msgInfo, uint32_t profileId,
-            uint8_t msgType, PacketBuffer *payload);
-    static void IncomingPartialUpdateRequest(nl::Weave::ExchangeContext *ec, const nl::Weave::IPPacketInfo *pktInfo,
-            const nl::Weave::WeaveMessageInfo *msgInfo, uint32_t profileId,
-            uint8_t msgType, PacketBuffer *payload);
-    static void IncomingUpdateRequestHandler(nl::Weave::ExchangeContext *ec, const nl::Weave::IPPacketInfo *pktInfo,
-            const nl::Weave::WeaveMessageInfo *msgInfo, uint32_t profileId,
-            uint8_t msgType, PacketBuffer *payload);
 };
 
 static MockWdmSubscriptionResponderImpl gWdmSubscriptionResponder;
@@ -404,6 +399,8 @@
     mSourceCatalog.Add(0, &mLocaleSettingsDataSource, mTraitHandleSet[kLocaleSettingsTraitSourceIndex]);
     mSourceCatalog.Add(0, &mBoltLockSettingDataSource, mTraitHandleSet[kBoltLockSettingTraitSourceIndex]);
     mSourceCatalog.Add(0, &mApplicationKeysTraitDataSource, mTraitHandleSet[kApplicationKeysTraitSourceIndex]);
+    mSourceCatalog.Add(0, &mTestCDataSource, mTraitHandleSet[kTestCTraitSourceIndex]);
+    mSourceCatalog.Add(0, &mLocaleCapabilitiesDataSource, mTraitHandleSet[kLocaleCapabilitiesTraitSourceIndex]);
 
     switch (mTestCaseId)
     {
@@ -478,16 +475,6 @@
     mSinkAddressList[kTestBDataSinkIndex] = &mTestBDataSink;
     mSinkAddressList[kLocaleCapabilitiesTraitSinkIndex] = &mLocaleCapabilitiesDataSink;
 
-    err = mExchangeMgr->RegisterUnsolicitedMessageHandler(nl::Weave::Profiles::kWeaveProfile_WDM,
-                                                          kMsgType_UpdateRequest,
-                                                          IncomingUpdateRequest,
-                                                          this);
-    SuccessOrExit(err);
-    err = mExchangeMgr->RegisterUnsolicitedMessageHandler(nl::Weave::Profiles::kWeaveProfile_WDM,
-                                                          kMsgType_PartialUpdateRequest,
-                                                          IncomingPartialUpdateRequest,
-                                                          this);
-    SuccessOrExit(err);
     Command_End();
 
 exit:
@@ -1080,160 +1067,6 @@
     pResponder->Command_End(true);
 }
 
-void MockWdmSubscriptionResponderImpl::IncomingUpdateRequestHandler(nl::Weave::ExchangeContext *ec, const nl::Weave::IPPacketInfo *pktInfo,
-    const nl::Weave::WeaveMessageInfo *msgInfo, uint32_t profileId,
-            uint8_t msgType, PacketBuffer *payload)
-{
-    switch (msgType)
-    {
-        case kMsgType_UpdateRequest:
-            IncomingUpdateRequest(ec, pktInfo, msgInfo, profileId, msgType, payload);
-            break;
-
-        case kMsgType_PartialUpdateRequest:
-            IncomingPartialUpdateRequest(ec, pktInfo, msgInfo, profileId, msgType, payload);
-            break;
-
-        default:
-            WeaveLogError(DataManagement, "Unexpected message with type 0x" PRIu8 "");
-            PacketBuffer::Free(payload);
-            ec->Close();
-            break;
-    }
-}
-
-void MockWdmSubscriptionResponderImpl::IncomingUpdateRequest(nl::Weave::ExchangeContext *ec, const nl::Weave::IPPacketInfo *pktInfo,
-    const nl::Weave::WeaveMessageInfo *msgInfo, uint32_t profileId,
-            uint8_t msgType, PacketBuffer *payload)
-{
-    WEAVE_ERROR     err     = WEAVE_NO_ERROR;
-    nl::Weave::TLV::TLVReader reader;
-    nl::Weave::TLV::TLVWriter writer;
-    UpdateRequest::Parser parser;
-    UpdateResponse::Builder updateResponseBuilder;
-    StatusReport statusReport;
-    uint8_t updateResponseBuf[512];
-    ReferencedTLVData referenceTLVData;
-    PacketBuffer * mBuf   = PacketBuffer::NewWithAvailableSize(1024);
-    MockWdmSubscriptionResponderImpl * pResponder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(ec->AppState);
-
-    VerifyOrExit(NULL != pResponder, err = WEAVE_ERROR_INCORRECT_STATE);
-
-    WeaveLogDetail(DataManagement, "Incoming Update Request, dumping it");
-
-    reader.Init(payload);
-    reader.Next();
-    DebugPrettyPrint(reader);
-
-    WeaveLogDetail(DataManagement, "constructing notification if subscription exists and status report");
-
-    if (pResponder->mUpdateTiming != MockWdmNodeOptions::kTiming_NoSub)
-    {
-        pResponder->mLocaleSettingsDataSource.Mutate();
-        SubscriptionEngine::GetInstance()->GetNotificationEngine()->Run();
-    }
-
-    writer.Init(updateResponseBuf, sizeof(updateResponseBuf));
-    err = updateResponseBuilder.Init(&writer);
-    SuccessOrExit(err);
-
-    {
-        VersionList::Builder &lVLBuilder = updateResponseBuilder.CreateVersionListBuilder();
-        lVLBuilder.AddVersion(pResponder->mLocaleSettingsDataSource.GetVersion());
-        lVLBuilder.EndOfVersionList();
-        SuccessOrExit(lVLBuilder.GetError());
-    }
-
-    {
-        StatusList::Builder &lSLBuilder = updateResponseBuilder.CreateStatusListBuilder();
-        lSLBuilder.AddStatus(nl::Weave::Profiles::kWeaveProfile_Common, nl::Weave::Profiles::Common::kStatus_Success);
-        lSLBuilder.EndOfStatusList();
-        SuccessOrExit(lSLBuilder.GetError());
-    }
-
-    updateResponseBuilder.EndOfResponse();
-    SuccessOrExit(updateResponseBuilder.GetError());
-
-    referenceTLVData.init(sizeof(updateResponseBuf), sizeof(updateResponseBuf), updateResponseBuf);
-
-    statusReport.init(nl::Weave::Profiles::kWeaveProfile_Common, nl::Weave::Profiles::Common::kStatus_Success, &referenceTLVData);
-    err = statusReport.pack(mBuf);
-    SuccessOrExit(err);
-
-    err = ec->SendMessage(nl::Weave::Profiles::kWeaveProfile_Common, nl::Weave::Profiles::Common::kMsgType_StatusReport, mBuf, nl::Weave::ExchangeContext::kSendFlag_RequestAck);
-    mBuf = NULL;
-    SuccessOrExit(err);
-
-exit:
-    WeaveLogFunctError(err);
-
-    if (NULL != payload)
-    {
-        PacketBuffer::Free(payload);
-        payload = NULL;
-    }
-
-    if (NULL != mBuf)
-    {
-        PacketBuffer::Free(mBuf);
-        mBuf = NULL;
-    }
-
-    if (NULL != ec)
-    {
-        ec->Close();
-    }
-}
-
-void MockWdmSubscriptionResponderImpl::IncomingPartialUpdateRequest(nl::Weave::ExchangeContext *ec, const nl::Weave::IPPacketInfo *pktInfo,
-    const nl::Weave::WeaveMessageInfo *msgInfo, uint32_t profileId,
-            uint8_t msgType, PacketBuffer *payload)
-{
-    WEAVE_ERROR     err     = WEAVE_NO_ERROR;
-    nl::Weave::TLV::TLVReader reader;
-    UpdateRequest::Parser parser;
-    WeaveLogDetail(DataManagement, "Incoming PartialUpdate Request");
-
-    // Set the handler on the EC, as we'll get more requests on this exchange.
-    ec->OnMessageReceived = IncomingUpdateRequestHandler;
-
-    reader.Init(payload);
-    reader.Next();
-    parser.Init(reader);
-    parser.CheckSchemaValidity();
-
-    reader.Init(payload);
-    DebugPrettyPrint(reader);
-
-    PacketBuffer * msgBuf   = PacketBuffer::NewWithAvailableSize(0);
-    VerifyOrExit(NULL != msgBuf, err = WEAVE_ERROR_NO_MEMORY);
-
-    err = ec->SendMessage(nl::Weave::Profiles::kWeaveProfile_WDM,
-                          nl::Weave::Profiles::DataManagement::kMsgType_UpdateContinue,
-                          msgBuf,
-                          nl::Weave::ExchangeContext::kSendFlag_RequestAck);
-    msgBuf = NULL;
-    SuccessOrExit(err);
-
-exit:
-    WeaveLogFunctError(err);
-
-    if (NULL != payload)
-    {
-        PacketBuffer::Free(payload);
-        payload = NULL;
-    }
-
-    if (NULL != msgBuf)
-    {
-        PacketBuffer::Free(msgBuf);
-        msgBuf = NULL;
-    }
-
-    // Don't close the EC; more requests fill follow.
-    // TODO: we should close the EC on a timeout.
-}
-
 void MockWdmSubscriptionResponderImpl::OnMessageReceivedForCustomCommand (nl::Weave::ExchangeContext *aEC, const nl::Inet::IPPacketInfo *aPktInfo,
         const nl::Weave::WeaveMessageInfo *aMsgInfo, uint32_t aProfileId,
         uint8_t aMsgType, PacketBuffer *aPayload)
diff --git a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_01.py b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_01.py
index f6d6d05..b4839a3 100755
--- a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_01.py
+++ b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_01.py
@@ -57,13 +57,14 @@
         wdm_next_args['client_clear_state_between_iterations'] = False
         wdm_next_args['server_clear_state_between_iterations'] = False
 
-        wdm_next_args['client_update_mutation'] = "OneLeaf"
+        wdm_next_args['client_update_mutation'] = "SameLevelLeaves"
         wdm_next_args['client_update_conditionality'] = "Conditional"
-        wdm_next_args['client_update_num_mutations'] = 1
+        wdm_next_args['client_update_num_mutations'] = 2
+        wdm_next_args['client_update_num_traits'] = 2
         wdm_next_args['client_update_timing'] = "AfterSub"
 
-        wdm_next_args['client_log_check'] = [('Update: path result: success', wdm_next_args['test_client_iterations'] * wdm_next_args['total_client_count'])]
-        wdm_next_args['server_log_check'] = []
+        wdm_next_args['client_log_check'] = [('UpdateComplete event: 1', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
+        wdm_next_args['server_log_check'] = [('Send Update Response with profileId 0x0 statusCode 0x0', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
         wdm_next_args['test_tag'] = self.__class__.__name__[19:].upper()
         wdm_next_args['test_case_name'] = ['Update 01: Client creates mutual subscription, sends conditional update request to publisher, and receives notification and status report']
         print 'test file: ' + self.__class__.__name__
diff --git a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_02.py b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_02.py
index 7c231cd..815d529 100755
--- a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_02.py
+++ b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_02.py
@@ -57,13 +57,14 @@
         wdm_next_args['client_clear_state_between_iterations'] = False
         wdm_next_args['server_clear_state_between_iterations'] = False
 
-        wdm_next_args['client_update_mutation'] = "OneLeaf"
+        wdm_next_args['client_update_mutation'] = "SameLevelLeaves"
         wdm_next_args['client_update_conditionality'] = "Unconditional"
-        wdm_next_args['client_update_num_mutations'] = 1
+        wdm_next_args['client_update_num_mutations'] = 2
+        wdm_next_args['client_update_num_traits'] = 2
         wdm_next_args['client_update_timing'] = "AfterSub"
 
-        wdm_next_args['client_log_check'] = [('Update: path result: success', wdm_next_args['test_client_iterations'] * wdm_next_args['total_client_count'])]
-        wdm_next_args['server_log_check'] = []
+        wdm_next_args['client_log_check'] = [('UpdateComplete event: 1', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
+        wdm_next_args['server_log_check'] = [('Send Update Response with profileId 0x0 statusCode 0x0', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
         wdm_next_args['test_tag'] = self.__class__.__name__[19:].upper()
         wdm_next_args['test_case_name'] = ['Update 02: Client creates mutual subscription, sends unconditional update request to publisher, and receives notification and status report']
         print 'test file: ' + self.__class__.__name__
diff --git a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_03.py b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_03.py
index 3ae7e53..f198f17 100755
--- a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_03.py
+++ b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_03.py
@@ -56,13 +56,14 @@
         wdm_next_args['client_clear_state_between_iterations'] = False
         wdm_next_args['server_clear_state_between_iterations'] = False
 
-        wdm_next_args['client_update_mutation'] = "OneLeaf"
+        wdm_next_args['client_update_mutation'] = "SameLevelLeaves"
         wdm_next_args['client_update_conditionality'] = "Unconditional"
-        wdm_next_args['client_update_num_mutations'] = 1
+        wdm_next_args['client_update_num_mutations'] = 2
+        wdm_next_args['client_update_num_traits'] = 2
         wdm_next_args['client_update_timing'] = "NoSub"
 
-        wdm_next_args['client_log_check'] = [('Update: path result: success', wdm_next_args['test_client_iterations'] * wdm_next_args['total_client_count'])]
-        wdm_next_args['server_log_check'] = []
+        wdm_next_args['client_log_check'] = [('UpdateComplete event: 1', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
+        wdm_next_args['server_log_check'] = [('Send Update Response with profileId 0x0 statusCode 0x0', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
         wdm_next_args['test_tag'] = self.__class__.__name__[19:].upper()
         wdm_next_args['test_case_name'] = ['Update 03: Client sends standalone unconditional update request to publisher, and receives status report']
         print 'test file: ' + self.__class__.__name__
diff --git a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_04.py b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_04.py
new file mode 100755
index 0000000..71629b8
--- /dev/null
+++ b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_04.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+
+#
+#    Copyright (c) 2019 Google, LLC.
+#    All rights reserved.
+#
+#    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.
+#
+
+#
+#    @file
+#       Calls Weave WDM Update between nodes.
+#       Update 04: Client sends standalone unconditional update request to publisher during subscription, and receives
+#       status report and notification.
+
+import unittest
+import set_test_path
+from weave_wdm_next_test_base import weave_wdm_next_test_base
+import WeaveUtilities
+
+
+class test_weave_wdm_next_update_04(weave_wdm_next_test_base):
+
+    def test_weave_wdm_next_mutual_subscribe_04(self):
+        wdm_next_args = {}
+        wdm_next_args['wdm_option'] = "mutual_subscribe"
+
+        wdm_next_args['total_client_count'] = 1
+        wdm_next_args['final_client_status'] = 0
+        wdm_next_args['timer_client_period'] = 10000
+        wdm_next_args['test_client_iterations'] = 1
+        wdm_next_args['test_client_delay'] = 2000
+        wdm_next_args['enable_client_flip'] = 1
+        wdm_next_args['test_client_case'] = 10 # kTestCase_TestUpdatableTrait
+
+        wdm_next_args['enable_retry'] = True
+
+        wdm_next_args['total_server_count'] = 0
+        wdm_next_args['final_server_status'] = 4
+        wdm_next_args['timer_server_period'] = 0
+        wdm_next_args['enable_server_flip'] = 0
+        wdm_next_args['test_server_case'] = 10
+
+        wdm_next_args['client_clear_state_between_iterations'] = False
+        wdm_next_args['server_clear_state_between_iterations'] = False
+
+        wdm_next_args['client_update_mutation'] = "SameLevelLeaves"
+        wdm_next_args['client_update_conditionality'] = "Unconditional"
+        wdm_next_args['client_update_num_mutations'] = 2
+        wdm_next_args['client_update_num_traits'] = 2
+        wdm_next_args['client_update_timing'] = "DuringSub"
+
+        wdm_next_args['client_log_check'] = [('UpdateComplete event: 1', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
+        wdm_next_args['server_log_check'] = [('Send Update Response with profileId 0x0 statusCode 0x0', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
+        wdm_next_args['test_tag'] = self.__class__.__name__[19:].upper()
+        wdm_next_args['test_case_name'] = ['Update 04: Client sends standalone unconditional update request to publisher during subscription, and receives status report and notification']
+        print 'test file: ' + self.__class__.__name__
+        print "weave-wdm-next update test 04"
+        super(test_weave_wdm_next_update_04, self).weave_wdm_next_test_base(wdm_next_args)
+
+
+if __name__ == "__main__":
+    WeaveUtilities.run_unittest()
diff --git a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_05.py b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_05.py
new file mode 100755
index 0000000..4068cbb
--- /dev/null
+++ b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_update_05.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+
+#
+#    Copyright (c) 2019 Google, LLC.
+#    Copyright (c) 2016-2018 Nest Labs, Inc.
+#    All rights reserved.
+#
+#    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.
+#
+
+#
+#    @file
+#       Calls Weave WDM Update between nodes.
+#       Update 05: Client sends standalone unconditional update request to publisher, and receives status report
+#
+
+import unittest
+import set_test_path
+from weave_wdm_next_test_base import weave_wdm_next_test_base
+import WeaveUtilities
+
+
+class test_weave_wdm_next_update_05(weave_wdm_next_test_base):
+
+    def test_weave_wdm_next_mutual_subscribe_05(self):
+        wdm_next_args = {}
+        wdm_next_args['wdm_option'] = "mutual_subscribe"
+
+        wdm_next_args['total_client_count'] = 1
+        wdm_next_args['final_client_status'] = 0
+        wdm_next_args['timer_client_period'] = 10000
+        wdm_next_args['test_client_iterations'] = 1
+        wdm_next_args['test_client_delay'] = 2000
+        wdm_next_args['enable_client_flip'] = 1
+        wdm_next_args['test_client_case'] = 10 # kTestCase_TestUpdatableTrait
+
+        wdm_next_args['enable_retry'] = True
+
+        wdm_next_args['total_server_count'] = 0
+        wdm_next_args['final_server_status'] = 4
+        wdm_next_args['timer_server_period'] = 0
+        wdm_next_args['enable_server_flip'] = 0
+        wdm_next_args['test_server_case'] = 10
+
+        wdm_next_args['client_clear_state_between_iterations'] = False
+        wdm_next_args['server_clear_state_between_iterations'] = False
+
+        wdm_next_args['client_update_mutation'] = "SameLevelLeaves"
+        wdm_next_args['client_update_conditionality'] = "Mixed"
+        wdm_next_args['client_update_num_mutations'] = 2
+        wdm_next_args['client_update_num_traits'] = 2
+        wdm_next_args['client_update_timing'] = "AfterSub"
+
+        wdm_next_args['client_log_check'] = [('UpdateComplete event: 1', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
+        wdm_next_args['server_log_check'] = [('Send Update Response with profileId 0x0 statusCode 0x0', wdm_next_args['test_client_iterations'] * wdm_next_args['client_update_num_mutations'])]
+        wdm_next_args['test_tag'] = self.__class__.__name__[19:].upper()
+        wdm_next_args['test_case_name'] = ['Update 05: Client sends standalone unconditional update request to publisher, and receives status report']
+        print 'test file: ' + self.__class__.__name__
+        print "weave-wdm-next update test 05"
+        super(test_weave_wdm_next_update_05, self).weave_wdm_next_test_base(wdm_next_args)
+
+
+if __name__ == "__main__":
+    WeaveUtilities.run_unittest()
diff --git a/src/test-apps/mock-device.cpp b/src/test-apps/mock-device.cpp
index 7c8b981..5c9ec1c 100644
--- a/src/test-apps/mock-device.cpp
+++ b/src/test-apps/mock-device.cpp
@@ -104,6 +104,7 @@
 static void InitiateConnection(System::Layer* aSystemLayer, void* aAppState, System::Error aError);
 static void HandleConnectionComplete(WeaveConnection *con, WEAVE_ERROR conErr);
 static void HandleWdmCompleteTest();
+static void HandleError();
 
 #if CONFIG_BLE_PLATFORM_BLUEZ
 bool EnableWeaveBluezPeripheral = false;
@@ -766,6 +767,111 @@
 
 #endif // CONFIG_BLE_PLATFORM_BLUEZ
 
+    InitializeEventLogging(&ExchangeMgr);
+
+    switch (gMockWdmNodeOptions.mWdmRoleInTest)
+    {
+        case 0:
+            break;
+        case kToolOpt_WdmInitMutualSubscription:
+        case kToolOpt_WdmSubscriptionClient:
+
+            if (gMockWdmNodeOptions.mWdmPublisherNodeId != kAnyNodeId)
+            {
+                err = MockWdmSubscriptionInitiator::GetInstance()->Init(&ExchangeMgr,
+                                                                        gGroupKeyEncOptions.GetEncKeyId(),
+                                                                        gWeaveSecurityMode.SecurityMode,
+                                                                        gMockWdmNodeOptions);
+                FAIL_ERROR(err, "MockWdmSubscriptionInitiator.Init failed");
+                MockWdmSubscriptionInitiator::GetInstance()->onCompleteTest = HandleWdmCompleteTest;
+                MockWdmSubscriptionInitiator::GetInstance()->onError = HandleError;
+
+            }
+            else
+            {
+                err = WEAVE_ERROR_INVALID_ARGUMENT;
+                FAIL_ERROR(err, "MockWdmSubscriptionInitiator requires node ID to some publisher");
+            }
+
+            break;
+        case kToolOpt_WdmRespMutualSubscription:
+        case kToolOpt_WdmSubscriptionPublisher:
+            if (gMockWdmNodeOptions.mEnableRetry)
+            {
+                err = WEAVE_ERROR_INVALID_ARGUMENT;
+                FAIL_ERROR(err, "MockWdmSubcriptionResponder is incompatible with --enable-retry");
+            }
+
+            err = MockWdmSubscriptionResponder::GetInstance()->Init(&ExchangeMgr,
+                                                                    gMockWdmNodeOptions
+                                                                    );
+            FAIL_ERROR(err, "MockWdmSubscriptionResponder.Init failed");
+            MockWdmSubscriptionResponder::GetInstance()->onCompleteTest = HandleWdmCompleteTest;
+            MockWdmSubscriptionResponder::GetInstance()->onError = HandleError;
+            if (gTestWdmNextOptions.mClearDataSinkState)
+            {
+                MockWdmSubscriptionResponder::GetInstance()->ClearDataSinkState();
+            }
+            break;
+        default:
+            err = WEAVE_ERROR_INVALID_ARGUMENT;
+            FAIL_ERROR(err, "WdmRoleInTest is invalid");
+    };
+
+    for (uint32_t iteration = 1; iteration <= gTestWdmNextOptions.mTestIterations; iteration++) {
+
+        switch (gMockWdmNodeOptions.mWdmRoleInTest) {
+            case 0:
+                break;
+            case kToolOpt_WdmInitMutualSubscription:
+            case kToolOpt_WdmSubscriptionClient:
+                if (gTestWdmNextOptions.mClearDataSinkState) {
+                    MockWdmSubscriptionInitiator::GetInstance()->ClearDataSinkState();
+                }
+                err = MockWdmSubscriptionInitiator::GetInstance()->StartTesting(gMockWdmNodeOptions.mWdmPublisherNodeId,
+                                                                                gMockWdmNodeOptions.mWdmUseSubnetId);
+                if (err != WEAVE_NO_ERROR) {
+                    printf("\nMockWdmSubscriptionInitiator.StartTesting failed: %s\n", ErrorStr(err));
+                    Done = true;
+                }
+                //FAIL_ERROR(err, "MockWdmSubscriptionInitiator.StartTesting failed");
+                break;
+            default:
+                printf("TestWdmNext server is ready\n");
+        };
+
+        switch (gMockWdmNodeOptions.mEventGeneratorType) {
+            case MockWdmNodeOptions::kGenerator_None:
+                gEventGenerator = NULL;
+                break;
+            case MockWdmNodeOptions::kGenerator_TestDebug:
+                gEventGenerator = GetTestDebugGenerator();
+                break;
+            case MockWdmNodeOptions::kGenerator_TestLiveness:
+                gEventGenerator = GetTestLivenessGenerator();
+                break;
+            case MockWdmNodeOptions::kGenerator_TestSecurity:
+                gEventGenerator = GetTestSecurityGenerator();
+                break;
+            case MockWdmNodeOptions::kGenerator_TestTelemetry:
+                gEventGenerator = GetTestTelemetryGenerator();
+                break;
+            case MockWdmNodeOptions::kGenerator_TestTrait:
+                gEventGenerator = GetTestTraitGenerator();
+                break;
+            case MockWdmNodeOptions::kGenerator_NumItems:
+            default:
+                gEventGenerator = NULL;
+                break;
+        }
+
+        if (gEventGenerator != NULL) {
+            printf("Starting Event Generator\n");
+            MockEventGenerator::GetInstance()->Init(&ExchangeMgr, gEventGenerator,
+                                                    gMockWdmNodeOptions.mTimeBetweenEvents, true);
+        }
+
+    }
     while (!Done)
     {
         struct timeval sleepTime;
@@ -1069,3 +1175,8 @@
         Done = true;
     }
 }
+
+static void HandleError()
+{
+    Done = true;
+}