Merge pull request #691 from mburshteyn1/textdescriptorreader-fix

Fix error in TextDescriptorReader when data contains leading empty spaces
diff --git a/Makefile-iOS b/Makefile-iOS
index 4d8c33f..b9b9de6 100644
--- a/Makefile-iOS
+++ b/Makefile-iOS
@@ -111,7 +111,9 @@
 TargetTupleStem                                         = apple-darwin
 TargetTuple                                             = $(TargetTupleStem)-ios
 
-ARCHS                                                   = arm64 armv7 armv7s i386 x86_64
+DEVICE_ARCHS                                            = arm64 armv7 armv7s
+SIMULATOR_ARCHS                                         = i386 x86_64
+ARCHS                                                   = $(DEVICE_ARCHS) $(SIMULATOR_ARCHS)
 
 TopTargetLibDir                                         = $(TopResultDir)/$(if $(1),$(1)-,)$(TargetTuple)/lib
 
@@ -138,11 +140,14 @@
 FrameworkModuleMap                                      = $(Framework)/$(FrameworkModulesDirName)/$(FrameworkModuleMapName)
 
 FRAMEWORK_ARCHFLAGS                                     = $(addprefix -arch ,$(ARCHS))
+DEVICE_XARCHS                                           = $(foreach arch, $(DEVICE_ARCHS),-Xarch_$(arch) -isysroot$(IOS_DEVICE_SDK))
+SIMULATOR_XARCHS                                        = $(foreach arch, $(SIMULATOR_ARCHS),-Xarch_$(arch) -isysroot$(IOS_SIMULATOR_SDK))
 FRAMEWORK_FLAGS                                         = \
         $(FRAMEWORK_ARCHFLAGS) \
         $(IOS_MIN_VERSION_FLAG) \
         $(FRAMEWORK_ARCHFLAGS) \
-        -isysroot $(IOS_DEVICE_SDK) \
+	$(DEVICE_XARCHS) \
+	$(SIMULATOR_XARCHS) \
         -I$(IOS_DEVICE_SDK)/$(CoreFoundationHeaders) \
         -fpic \
         -lc++ \
diff --git a/build/config/android/WeaveProjectConfig.h b/build/config/android/WeaveProjectConfig.h
index 5318eb0..60e96c4 100644
--- a/build/config/android/WeaveProjectConfig.h
+++ b/build/config/android/WeaveProjectConfig.h
@@ -26,7 +26,7 @@
 #define WEAVEPROJECTCONFIG_H
 
 // Enable use of an ephemeral UDP source port for locally initiated Weave exchanges.
-#define WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT 1
+#define WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT 0
 
 // Enable UDP listening on demand in the WeaveDeviceManager
 #define WEAVE_CONFIG_DEVICE_MGR_DEMAND_ENABLE_UDP 1
diff --git a/build/config/ios/WeaveProjectConfig.h b/build/config/ios/WeaveProjectConfig.h
index a2ec644..e28c206 100644
--- a/build/config/ios/WeaveProjectConfig.h
+++ b/build/config/ios/WeaveProjectConfig.h
@@ -26,7 +26,7 @@
 #define WEAVEPROJECTCONFIG_H
 
 // Enable use of an ephemeral UDP source port for locally initiated Weave exchanges.
-#define WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT 1
+#define WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT 0
 
 // Enable UDP listening on demand in the WeaveDeviceManager
 #define WEAVE_CONFIG_DEVICE_MGR_DEMAND_ENABLE_UDP 1
diff --git a/src/ble/BleApplicationDelegate.h b/src/ble/BleApplicationDelegate.h
index c2f2111..e5d7690 100644
--- a/src/ble/BleApplicationDelegate.h
+++ b/src/ble/BleApplicationDelegate.h
@@ -36,6 +36,9 @@
 class NL_DLL_EXPORT BleApplicationDelegate
 {
 public:
+    virtual ~BleApplicationDelegate() {
+    }
+
     // Weave calls this function once it closes the last BLEEndPoint associated with a BLE given connection object.
     // A call to this function means Weave no longer cares about the state of the given BLE connection.
     // The application can use this callback to e.g. close the underlying BLE conection if it is no longer needed,
diff --git a/src/ble/BlePlatformDelegate.h b/src/ble/BlePlatformDelegate.h
index 4425cec..e79dd8e 100644
--- a/src/ble/BlePlatformDelegate.h
+++ b/src/ble/BlePlatformDelegate.h
@@ -40,6 +40,9 @@
 class NL_DLL_EXPORT BlePlatformDelegate
 {
 public:
+    virtual ~BlePlatformDelegate() {
+    }
+
     // Following APIs must be implemented by platform:
 
     // Subscribe to updates and indications on the specfied characteristic
diff --git a/src/device-manager/WeaveDataManagementClient.cpp b/src/device-manager/WeaveDataManagementClient.cpp
index e47e672..8be8697 100644
--- a/src/device-manager/WeaveDataManagementClient.cpp
+++ b/src/device-manager/WeaveDataManagementClient.cpp
@@ -575,7 +575,6 @@
 {
     WEAVE_ERROR err                                       = WEAVE_NO_ERROR;
     TraitSchemaEngine::IGetDataDelegate * getDataDelegate = NULL;
-    TLVType dummyContainerType;
     nl::Weave::TLV::TLVWriter writer;
     PropertyPathHandle propertyPathHandle = kNullPropertyPathHandle;
 
@@ -751,8 +750,6 @@
 WEAVE_ERROR GenericTraitUpdatableDataSink::DeleteData(const char * apPath)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
-    nl::Weave::TLV::TLVReader reader;
-    PacketBuffer * pMsgBuf                = NULL;
     PropertyPathHandle propertyPathHandle = kNullPropertyPathHandle;
     std::map<PropertyPathHandle, PacketBuffer *>::iterator it;
 
diff --git a/src/device-manager/WeaveDataManagementClient.h b/src/device-manager/WeaveDataManagementClient.h
index 8b96878..1cea9b8 100644
--- a/src/device-manager/WeaveDataManagementClient.h
+++ b/src/device-manager/WeaveDataManagementClient.h
@@ -137,10 +137,6 @@
     void * mpAppState;
 
 private:
-    union
-    {
-        DMCompleteFunct General;
-    } mOnComplete;
     DMErrorFunct mOnError;
 
     template <class T>
diff --git a/src/device-manager/WeaveDeviceManager.h b/src/device-manager/WeaveDeviceManager.h
index 99c23cc..95d97e4 100644
--- a/src/device-manager/WeaveDeviceManager.h
+++ b/src/device-manager/WeaveDeviceManager.h
@@ -136,11 +136,11 @@
     WEAVE_ERROR PassiveRendezvousDevice(const uint8_t *accessToken, uint32_t accessTokenLen, void *appReqState, CompleteFunct onComplete, ErrorFunct onError);
 #if CONFIG_NETWORK_LAYER_BLE
     WEAVE_ERROR ConnectBle(BLE_CONNECTION_OBJECT connObj,
-        void *appReqState, CompleteFunct onComplete, ErrorFunct onError, bool autoClose = false);
+        void *appReqState, CompleteFunct onComplete, ErrorFunct onError, bool autoClose = true);
     WEAVE_ERROR ConnectBle(BLE_CONNECTION_OBJECT connObj, const char *pairingCode,
-        void *appReqState, CompleteFunct onComplete, ErrorFunct onError, bool autoClose = false);
+        void *appReqState, CompleteFunct onComplete, ErrorFunct onError, bool autoClose = true);
     WEAVE_ERROR ConnectBle(BLE_CONNECTION_OBJECT connObj, const uint8_t *accessToken, uint32_t accessTokenLen,
-        void *appReqState, CompleteFunct onComplete, ErrorFunct onError, bool autoClose = false);
+        void *appReqState, CompleteFunct onComplete, ErrorFunct onError, bool autoClose = true);
 #endif // CONFIG_NETWORK_LAYER_BLE
 
     // ----- Remote Passive Rendezvous -----
diff --git a/src/device-manager/cocoa/Makefile.am b/src/device-manager/cocoa/Makefile.am
index 0f2c976..5a1cd7f 100644
--- a/src/device-manager/cocoa/Makefile.am
+++ b/src/device-manager/cocoa/Makefile.am
@@ -63,6 +63,7 @@
     NLWeavePasscodeEncryptionSupport.h     \
     NLWeaveKeyExportClient.h               \
     NLWeaveKeyExportSupport.h              \
+    NLWeaveLogging.h                       \
     NLWdmClient.h                          \
     NLGenericTraitUpdatableDataSink.h      \
     NLResourceIdentifier.h                 \
diff --git a/src/device-manager/cocoa/NLIdentifyDeviceCriteria_Protected.h b/src/device-manager/cocoa/NLIdentifyDeviceCriteria_Protected.h
index 9288d8d..f1e3e23 100644
--- a/src/device-manager/cocoa/NLIdentifyDeviceCriteria_Protected.h
+++ b/src/device-manager/cocoa/NLIdentifyDeviceCriteria_Protected.h
@@ -26,6 +26,7 @@
 
 #include "WeaveDeviceManager.h"
 #include <Weave/Profiles/device-description/DeviceDescription.h>
+#import "NLIdentifyDeviceCriteria.h"
 
 using nl::Weave::Profiles::DeviceDescription::IdentifyDeviceCriteria;
 
diff --git a/src/device-manager/cocoa/NLWeaveDeviceManager.h b/src/device-manager/cocoa/NLWeaveDeviceManager.h
index fc9d54e..c992591 100644
--- a/src/device-manager/cocoa/NLWeaveDeviceManager.h
+++ b/src/device-manager/cocoa/NLWeaveDeviceManager.h
@@ -180,7 +180,7 @@
 
 - (BOOL)isConnected;
 
-- (BOOL)isValidPairingCode:(NSString *)pairingCode;
++ (BOOL)isValidPairingCode:(NSString *)pairingCode;
 
 - (void)getCameraAuthData:(NSString *)nonce completion:(WDMCompletionBlock)completionBlock failure:(WDMFailureBlock)failureBlock;
 
diff --git a/src/device-manager/cocoa/NLWeaveDeviceManager.mm b/src/device-manager/cocoa/NLWeaveDeviceManager.mm
index 6f1d3ac..8190e88 100644
--- a/src/device-manager/cocoa/NLWeaveDeviceManager.mm
+++ b/src/device-manager/cocoa/NLWeaveDeviceManager.mm
@@ -308,11 +308,11 @@
             // Note that we're already in Weave work queue, which means all callbacks for the previous or current request
             // has either happened/completed or would be canceled by this call to Close. Therefore, it should be safe
             // to wipe out request context variables like _mRequestName and _mCompletionHandler.
-
             _mWeaveCppDM->Close();
 
             if (_blePeripheral) {
                 [[[NLWeaveStack sharedStack] BleDelegate] forceBleDisconnect_Sync:_blePeripheral];
+
                 // autoclose is disabled when running weave connect ble, close ble after woble stack is
                 // destroyed
                 // release reference to the CBPeripheral
@@ -347,11 +347,11 @@
     return result ? YES : NO;
 }
 
-- (BOOL)isValidPairingCode:(NSString *)pairingCode;
++ (BOOL)isValidPairingCode:(NSString *)pairingCode;
 {
     __block bool result = false;
 
-    WDM_LOG_METHOD_SIG();
+    WDM_LOG_DEBUG(@"isValidPairingCode");
 
     if ([pairingCode length] != 0) {
         // note we're not executing in any specific queue, as this subroutine is supposed to be 'static'
@@ -939,7 +939,7 @@
             _BleConnectionPreparationCompleteHandler = ^(NLWeaveDeviceManager * dm, WEAVE_ERROR err) {
                 if (WEAVE_NO_ERROR == err) {
                     err = _mWeaveCppDM->ConnectBle(
-                        (__bridge void *) _blePeripheral, (__bridge void *) self, HandleSimpleOperationComplete, onWeaveError);
+                        (__bridge void *) _blePeripheral, (__bridge void *) self, HandleSimpleOperationComplete, onWeaveError, false);
                 }
                 if (WEAVE_NO_ERROR != err) {
                     [dm DispatchAsyncDefaultFailureBlockWithCode:err];
@@ -979,7 +979,7 @@
                     const char * pairingCodeStr = [pairingCode UTF8String];
 
                     err = _mWeaveCppDM->ConnectBle((__bridge void *) _blePeripheral, pairingCodeStr, (__bridge void *) self,
-                        HandleSimpleOperationComplete, onWeaveError);
+                        HandleSimpleOperationComplete, onWeaveError, false);
                 }
                 if (WEAVE_NO_ERROR != err) {
                     [dm DispatchAsyncDefaultFailureBlockWithCode:err];
@@ -1073,7 +1073,7 @@
                     uint8_t * pAccessToken = (uint8_t *) [accessTokenData bytes];
 
                     err = _mWeaveCppDM->ConnectBle((__bridge void *) _blePeripheral, pAccessToken, accessTokenLen,
-                        (__bridge void *) self, HandleSimpleOperationComplete, onWeaveError);
+                        (__bridge void *) self, HandleSimpleOperationComplete, onWeaveError, false);
                 }
 
                 if (WEAVE_NO_ERROR != err) {
diff --git a/src/device-manager/cocoa/NLWeaveDeviceManagerTypes.h b/src/device-manager/cocoa/NLWeaveDeviceManagerTypes.h
index fafd39c..5251865 100644
--- a/src/device-manager/cocoa/NLWeaveDeviceManagerTypes.h
+++ b/src/device-manager/cocoa/NLWeaveDeviceManagerTypes.h
@@ -23,6 +23,7 @@
  */
 
 #import <Foundation/Foundation.h>
+#import "NLWeaveErrorCodes.h"
 
 #ifndef __NLWEAVEDEVICEMANAGERTYPES_H__
 #define __NLWEAVEDEVICEMANAGERTYPES_H__
diff --git a/src/device-manager/cocoa/NLWeaveLogging.h b/src/device-manager/cocoa/NLWeaveLogging.h
index 00289c3..3eac928 100644
--- a/src/device-manager/cocoa/NLWeaveLogging.h
+++ b/src/device-manager/cocoa/NLWeaveLogging.h
@@ -96,7 +96,7 @@
  */
 @interface NLWeaveLogging : NSObject
 
-#pragma Logging Configuration
+#pragma mark Logging Configuration
 
 /**
  * Sets the shared @c NLWeaveLogWriter to start receiving Weave logs.
@@ -108,7 +108,7 @@
  */
 + (void)setSharedLogWriter:(nullable id<NLWeaveLogWriter>)logWriter;
 
-#pragma Log Methods
+#pragma mark Log Methods
 
 /**
  * Internal handler method for logging a message to the console and notifying the shared log writer.
diff --git a/src/device-manager/cocoa/NLWeaveStack.mm b/src/device-manager/cocoa/NLWeaveStack.mm
index e9345b2..c647eb9 100644
--- a/src/device-manager/cocoa/NLWeaveStack.mm
+++ b/src/device-manager/cocoa/NLWeaveStack.mm
@@ -37,6 +37,8 @@
 #include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
 #include <Weave/Profiles/data-management/DataManagement.h>
 
+#include <array>
+
 using namespace nl::Weave::Profiles;
 using namespace nl::Weave::Profiles::DataManagement;
 
@@ -60,12 +62,6 @@
     nl::Ble::BleLayer _mBleLayer;
     NLWeaveBleDelegate * _mBleDelegate;
 #endif // #if CONFIG_NETWORK_LAYER_BLE
-    /*
-    int selectRes;
-    int MaxNumberedFdPlusOne;
-    struct timeval sleepTime;
-    fd_set readFDs, writeFDs, exceptFDs;
-     */
 }
 
 - (WEAVE_ERROR)InitStack_internal:(NSString *)listenAddr bleDelegate:(NLWeaveBleDelegate *)bleDelegate;
@@ -332,18 +328,20 @@
     WDM_LOG_DEBUG(@"Shutdown Weave System Layer\n");
     _mSystemLayer.Shutdown();
 
-    WDM_LOG_DEBUG(@"Shutdown completed\n");
-
-    self.currentState = kWeaveStack_QueueInitialized;
 
     if (WEAVE_NO_ERROR != err) {
         WDM_LOG_ERROR(@"Error in ShutdownStack_Stage2 : (%d) %@\n", err, [NSString stringWithUTF8String:nl::ErrorStr(err)]);
     }
 
-    // inform application layer about the completion, if so desired
-    if (block) {
-        block(err);
-    }
+    NSTimeInterval delay = 2.0;
+    WDM_LOG_DEBUG(@"Waiting %f seconds for rx/tx buffers to flush.\n", delay);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), _mWorkQueue, ^(void) {
+        WDM_LOG_DEBUG(@"Shutdown completed\n");
+        self.currentState = kWeaveStack_QueueInitialized;
+        if (block) {
+            block(err);
+        }
+    });
 }
 
 /**
@@ -382,8 +380,10 @@
 exit:
     if (WEAVE_NO_ERROR != err) {
         WDM_LOG_ERROR(@"Error in ShutdownStack_Stage1 : (%d) %@\n", err, [NSString stringWithUTF8String:nl::ErrorStr(err)]);
-
-        _mShutdownCompletionBlock(err);
+        if (_mShutdownCompletionBlock) {
+          _mShutdownCompletionBlock(err);
+          _mShutdownCompletionBlock = nil;
+        }
     }
 }
 
@@ -418,25 +418,19 @@
  */
 - (void)TryProcessNetworkEvents
 {
-    __block struct timeval sleepTime;
-    __block fd_set readFDs, writeFDs, exceptFDs;
-    int MaxNumberedFdPlusOne = 0;
     WEAVE_ERROR err = WEAVE_NO_ERROR;
 
     // WDM_LOG_METHOD_SIG();
 
+    int sleepTime = 10000;
+    __block std::array<struct pollfd, WEAVE_CONFIG_MAX_POLL_FDS> pollFDs;
+    int numPollFDs = 0;
+
     VerifyOrExit(kWeaveStack_FullyInitialized == self.currentState, err = WEAVE_ERROR_INCORRECT_STATE);
 
-    FD_ZERO(&readFDs);
-    FD_ZERO(&writeFDs);
-    FD_ZERO(&exceptFDs);
-
-    sleepTime.tv_sec = 10;
-    sleepTime.tv_usec = 0;
-
     // Collect the currently active file descriptors.
-    _mSystemLayer.PrepareSelect(MaxNumberedFdPlusOne, &readFDs, &writeFDs, &exceptFDs, sleepTime);
-    _mInetLayer.PrepareSelect(MaxNumberedFdPlusOne, &readFDs, &writeFDs, &exceptFDs, sleepTime);
+    _mSystemLayer.PrepareSelect(pollFDs.data(), numPollFDs, sleepTime);
+    _mInetLayer.PrepareSelect(pollFDs.data(), numPollFDs, sleepTime);
 
     // WDM_LOG_DEBUG(@"Sleeping for %f sec.\n", sleepTime.tv_sec + (sleepTime.tv_usec / 1000000.0));
 
@@ -447,7 +441,7 @@
         dispatch_async(_mSelectQueue, ^(void) {
             // Wait for for I/O or for the next timer to expire.
             // Note that this is not a good practice to use with GCD, but it's
-            int selectRes = select(MaxNumberedFdPlusOne, &readFDs, &writeFDs, &exceptFDs, &sleepTime);
+            int pollRes = poll(pollFDs.data(), numPollFDs, sleepTime);
 
             dispatch_async(_mWorkQueue, ^(void) {
                 _mIsWaitingOnSelect = false;
@@ -459,8 +453,8 @@
                     [self ShutdownStack_Stage2];
                 } else if (kWeaveStack_FullyInitialized == self.currentState) {
                     // Perform I/O and/or dispatch timers.
-                    _mSystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
-                    _mInetLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+                    _mSystemLayer.HandleSelectResult(pollFDs.data(), numPollFDs);
+                    _mInetLayer.HandleSelectResult(pollFDs.data(), numPollFDs);
 
                     // It's wierd that with iOS 9 SDK, we have to use disaptch_after here,
                     // instead of directly calling TryProcessNetworkEvents nor dispatch_async.
@@ -558,7 +552,7 @@
 {
     return;
 }
-    
+
 } // Platform
 
 } // WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
diff --git a/src/device-manager/java/WeaveDeviceManager-JNI.cpp b/src/device-manager/java/WeaveDeviceManager-JNI.cpp
index 3491723..65908ed 100644
--- a/src/device-manager/java/WeaveDeviceManager-JNI.cpp
+++ b/src/device-manager/java/WeaveDeviceManager-JNI.cpp
@@ -24,6 +24,7 @@
  *
  */
 
+#include <array>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -1910,9 +1911,6 @@
 {
     JNIEnv *env;
     JavaVMAttachArgs attachArgs;
-    struct timeval sleepTime;
-    fd_set readFDs, writeFDs, exceptFDs;
-    int numFDs = 0;
 
     // Attach the IO thread to the JVM as a daemon thread.  This allows the JVM to shutdown
     // without waiting for this thread to exit.
@@ -1933,23 +1931,24 @@
     // Loop until we told to exit.
     while (true)
     {
-        numFDs = 0;
-        FD_ZERO(&readFDs);
-        FD_ZERO(&writeFDs);
-        FD_ZERO(&exceptFDs);
-
-        sleepTime.tv_sec = 10;
-        sleepTime.tv_usec = 0;
+        int sleepTime = 10000;
+        struct pollfd pollFDs[WEAVE_CONFIG_MAX_POLL_FDS];
+        int numPollFDs = 0;
 
         // Collect the currently active file descriptors.
-        sSystemLayer.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, sleepTime);
-        sInet.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, sleepTime);
+        sSystemLayer.PrepareSelect(pollFDs, numPollFDs, sleepTime);
+        sInet.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 
         // Unlock the stack so that Java threads can make API calls.
         pthread_mutex_unlock(&sStackLock);
 
         // Wait for for I/O or for the next timer to expire.
-        int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &sleepTime);
+        int pollRes = poll(pollFDs, numPollFDs, sleepTime);
+        if (pollRes < 0)
+        {
+            printf("poll failed: %s\n", nl::ErrorStr(System::MapErrorPOSIX(errno)));
+            continue;
+        }
 
         // Break the loop if requested to shutdown.
         if (sShutdown)
@@ -1959,8 +1958,8 @@
         pthread_mutex_lock(&sStackLock);
 
         // Perform I/O and/or dispatch timers.
-        sSystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
-        sInet.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+        sSystemLayer.HandleSelectResult(pollFDs, numPollFDs);
+        sInet.HandleSelectResult(pollFDs, numPollFDs);
     }
 
     // Detach the thread from the JVM.
diff --git a/src/device-manager/python/WeaveDeviceManager-ScriptBinding.cpp b/src/device-manager/python/WeaveDeviceManager-ScriptBinding.cpp
index 7119252..4db957f 100644
--- a/src/device-manager/python/WeaveDeviceManager-ScriptBinding.cpp
+++ b/src/device-manager/python/WeaveDeviceManager-ScriptBinding.cpp
@@ -349,9 +349,10 @@
     ExitNow(err = WEAVE_ERROR_NOT_IMPLEMENTED);
 
 #else /* WEAVE_SYSTEM_CONFIG_USE_SOCKETS */
-    struct timeval sleepTime;
-    fd_set readFDs, writeFDs, exceptFDs;
-    int maxFDs = 0;
+    int sleepTime = sleepTimeMS;
+    struct pollfd pollFDs[WEAVE_CONFIG_MAX_POLL_FDS];
+    int numPollFDs = 0;
+    int blePollFD = -1;
 #if CONFIG_NETWORK_LAYER_BLE
     uint8_t bleWakeByte;
     bool result = false;
@@ -367,33 +368,30 @@
     } evu;
 #endif /* CONFIG_NETWORK_LAYER_BLE */
 
-    FD_ZERO(&readFDs);
-    FD_ZERO(&writeFDs);
-    FD_ZERO(&exceptFDs);
-
-    sleepTime.tv_sec = sleepTimeMS / 1000;
-    sleepTime.tv_usec = (sleepTimeMS % 1000) * 1000;
-
     if (sSystemLayer.State() == System::kLayerState_Initialized)
-        sSystemLayer.PrepareSelect(maxFDs, &readFDs, &writeFDs, &exceptFDs, sleepTime);
+        sSystemLayer.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 
     if (Inet.State == InetLayer::kState_Initialized)
-        Inet.PrepareSelect(maxFDs, &readFDs, &writeFDs, &exceptFDs, sleepTime);
+        Inet.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 
 #if CONFIG_NETWORK_LAYER_BLE
     // Add read end of BLE wake pipe to readFDs.
-    FD_SET(BleWakePipe[0], &readFDs);
-
-    if (BleWakePipe[0] + 1 > maxFDs)
-        maxFDs = BleWakePipe[0] + 1;
+    {
+        struct pollfd event;
+        event.fd = BleWakePipe[0];
+        event.events = POLLIN;
+        event.revents = 0;
+        blePollFD = numPollFDs;
+        pollFDs[numPollFDs++] = event;
+    }
 #endif /* CONFIG_NETWORK_LAYER_BLE */
 
-    int selectRes = select(maxFDs, &readFDs, &writeFDs, &exceptFDs, &sleepTime);
-    VerifyOrExit(selectRes >= 0, err = System::MapErrorPOSIX(errno));
+    int pollRes = poll(pollFDs, numPollFDs, sleepTime);
+    VerifyOrExit(pollRes >= 0, err = System::MapErrorPOSIX(errno));
 
 #if CONFIG_NETWORK_LAYER_BLE
     // Drive IO to InetLayer and/or BleLayer.
-    if (FD_ISSET(BleWakePipe[0], &readFDs))
+    if (pollFDs[blePollFD].revents != 0)
     {
         while (true)
         {
@@ -498,17 +496,14 @@
                 }
             }
         }
-
-        // Don't bother InetLayer if we only got BLE IO.
-        selectRes--;
     }
 #endif /* CONFIG_NETWORK_LAYER_BLE */
 
     if (sSystemLayer.State() == System::kLayerState_Initialized)
-        sSystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+        sSystemLayer.HandleSelectResult(pollFDs, numPollFDs);
 
     if (Inet.State == InetLayer::kState_Initialized)
-        Inet.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+        Inet.HandleSelectResult(pollFDs, numPollFDs);
 
 #endif /* WEAVE_SYSTEM_CONFIG_USE_SOCKETS */
 
@@ -1373,7 +1368,7 @@
 
         case nl::Weave::Binding::kEvent_DefaultCheck:
             WeaveLogDetail(DeviceManager, "kEvent_DefaultCheck");
-            // fall through
+            [[fallthrough]];
         default:
             nl::Weave::Binding::DefaultEventHandler(apAppState, aEvent, aInParam, aOutParam);
     }
diff --git a/src/device-manager/python/weave-device-mgr.py b/src/device-manager/python/weave-device-mgr.py
index 809e08a..3c943a9 100755
--- a/src/device-manager/python/weave-device-mgr.py
+++ b/src/device-manager/python/weave-device-mgr.py
@@ -41,8 +41,8 @@
 from copy import copy
 from cmd import Cmd
 
-from Cryptodome.Hash import CMAC
-from Cryptodome.Cipher import AES
+from cryptography.hazmat.primitives import cmac
+from cryptography.hazmat.primitives.ciphers import algorithms
 from six.moves import range
 from six.moves import zip
 
@@ -148,9 +148,9 @@
 
 
 def aes_cmac(key, message):
-    cipher = CMAC.new(key, ciphermod=AES)
+    cipher = cmac.CMAC.new(algorithms.AES(key))
     cipher.update(message)
-    return cipher.digest()
+    return cipher.finalize()
 
 
 #see RFC-4615
@@ -2602,3 +2602,4 @@
 
 if __name__ == "__main__":
     main()
+
diff --git a/src/examples/weave-app-common.cpp b/src/examples/weave-app-common.cpp
index d27c2bb..9f6b759 100644
--- a/src/examples/weave-app-common.cpp
+++ b/src/examples/weave-app-common.cpp
@@ -122,40 +122,31 @@
 void DriveIO(void)
 {
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-    struct timeval sleepTime;
-    fd_set readFDs, writeFDs, exceptFDs;
-    int numFDs = 0;
-    int selectRes;
-
-    // Use a sleep value of 100 milliseconds
-    sleepTime.tv_sec = 0;
-    sleepTime.tv_usec = NETWORK_SLEEP_TIME_MSECS;
-
-    FD_ZERO(&readFDs);
-    FD_ZERO(&writeFDs);
-    FD_ZERO(&exceptFDs);
+    int sleepTime = NETWORK_SLEEP_TIME_MSECS;
+    struct pollfd pollFDs[WEAVE_CONFIG_MAX_POLL_FDS];
+    int numPollFDs = 0;
 
     if (SystemLayer.State() == System::kLayerState_Initialized)
-        SystemLayer.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, sleepTime);
+        SystemLayer.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 
     if (Inet.State == InetLayer::kState_Initialized)
-        Inet.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, sleepTime);
+        Inet.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 
-    selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &sleepTime);
-    if (selectRes < 0)
+    int pollRes = poll(pollFDs, numPollFDs, sleepTime);
+    if (pollRes < 0)
     {
-        printf("select failed: %s\n", nl::ErrorStr(System::MapErrorPOSIX(errno)));
+        printf("poll failed: %s\n", nl::ErrorStr(System::MapErrorPOSIX(errno)));
         return;
     }
 
     if (SystemLayer.State() == System::kLayerState_Initialized)
     {
-        SystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+        SystemLayer.HandleSelectResult(pollFDs, numPollFDs);
     }
 
     if (Inet.State == InetLayer::kState_Initialized)
     {
-        Inet.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+        Inet.HandleSelectResult(pollFDs, numPollFDs);
     }
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 }
diff --git a/src/inet/IPAddress.cpp b/src/inet/IPAddress.cpp
index c78a857..246f238 100644
--- a/src/inet/IPAddress.cpp
+++ b/src/inet/IPAddress.cpp
@@ -53,19 +53,6 @@
     return Addr[0] != other.Addr[0] || Addr[1] != other.Addr[1] || Addr[2] != other.Addr[2] || Addr[3] != other.Addr[3];
 }
 
-IPAddress & IPAddress::operator=(const IPAddress& other)
-{
-    if (this != &other)
-    {
-        Addr[0] = other.Addr[0];
-        Addr[1] = other.Addr[1];
-        Addr[2] = other.Addr[2];
-        Addr[3] = other.Addr[3];
-    }
-
-    return *this;
-}
-
 #if WEAVE_SYSTEM_CONFIG_USE_LWIP
 
 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
diff --git a/src/inet/IPAddress.h b/src/inet/IPAddress.h
index c50d2f1..2379985 100644
--- a/src/inet/IPAddress.h
+++ b/src/inet/IPAddress.h
@@ -289,15 +289,6 @@
     bool operator !=(const IPAddress& other) const;
 
     /**
-     * @brief   Conventional assignment operator.
-     *
-     * @param[in]   other   The address to copy.
-     *
-     * @return  A reference to this object.
-     */
-    IPAddress& operator =(const IPAddress& other);
-
-    /**
      * @brief   Emit the IP address in conventional text presentation format.
      *
      * @param[out]  buf         The address of the emitted text.
diff --git a/src/inet/IPPrefix.cpp b/src/inet/IPPrefix.cpp
index 492f336..94abd72 100644
--- a/src/inet/IPPrefix.cpp
+++ b/src/inet/IPPrefix.cpp
@@ -53,17 +53,6 @@
     return IPAddr != other.IPAddr || Length != other.Length;
 }
 
-IPPrefix & IPPrefix::operator=(const IPPrefix& other)
-{
-    if (this != &other)
-    {
-        IPAddr = other.IPAddr;
-        Length = other.Length;
-    }
-
-    return *this;
-}
-
 bool IPPrefix::MatchAddress(const IPAddress& addr) const
 {
     uint8_t l = (Length <= 128) ? Length : 128;
diff --git a/src/inet/IPPrefix.h b/src/inet/IPPrefix.h
index 0d6e950..d8f19d6 100644
--- a/src/inet/IPPrefix.h
+++ b/src/inet/IPPrefix.h
@@ -100,15 +100,6 @@
     bool operator !=(const IPPrefix& other) const;
 
     /**
-     * @brief   Conventional assignment operator.
-     *
-     * @param[in]   other   the prefix to copy.
-     *
-     * @return  a reference to this object.
-     */
-    IPPrefix& operator =(const IPPrefix& other);
-
-    /**
      * @brief   Test if an address matches the prefix.
      *
      * @param[in]   addr   the address to test.
diff --git a/src/inet/InetLayer.cpp b/src/inet/InetLayer.cpp
index b0a4ad6..8638638 100644
--- a/src/inet/InetLayer.cpp
+++ b/src/inet/InetLayer.cpp
@@ -1411,20 +1411,12 @@
 /**
  *  Prepare the sets of file descriptors for @p select() to work with.
  *
- *  @param[out]    nfds       The range of file descriptors in the file
- *                            descriptor set.
- *
- *  @param[in]     readfds    A pointer to the set of readable file descriptors.
- *
- *  @param[in]     writefds   A pointer to the set of writable file descriptors.
- *
- *  @param[in]     exceptfds  A pointer to the set of file descriptors with errors.
- *
- * @param[in]      sleepTimeTV A pointer to a structure specifying how long the select should sleep
+ *  @param[in,out]  pollFDs     The fd set which is going to be polled
+ *  @param[in,out]  numPollFDs  The number of fds in the fd set
+ *  @param[in]      timeoutMS   A reference to the maximum sleep time.
  *
  */
-void InetLayer::PrepareSelect(int& nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
-        struct timeval& sleepTimeTV)
+void InetLayer::PrepareSelect(struct pollfd * pollFDs, int& numPollFDs, int& timeoutMS)
 {
     if (State != kState_Initialized)
         return;
@@ -1434,7 +1426,7 @@
     {
         RawEndPoint* lEndPoint = RawEndPoint::sPool.Get(*mSystemLayer, i);
         if ((lEndPoint != NULL) && lEndPoint->IsCreatedByInetLayer(*this))
-            lEndPoint->PrepareIO().SetFDs(lEndPoint->mSocket, nfds, readfds, writefds, exceptfds);
+            lEndPoint->PrepareIO().SetFDs(lEndPoint->mSocket, pollFDs, numPollFDs);
     }
 #endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
 
@@ -1443,7 +1435,7 @@
     {
         TCPEndPoint* lEndPoint = TCPEndPoint::sPool.Get(*mSystemLayer, i);
         if ((lEndPoint != NULL) && lEndPoint->IsCreatedByInetLayer(*this))
-            lEndPoint->PrepareIO().SetFDs(lEndPoint->mSocket, nfds, readfds, writefds, exceptfds);
+            lEndPoint->PrepareIO().SetFDs(lEndPoint->mSocket, pollFDs, numPollFDs);
     }
 #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
 
@@ -1452,7 +1444,7 @@
     {
         UDPEndPoint* lEndPoint = UDPEndPoint::sPool.Get(*mSystemLayer, i);
         if ((lEndPoint != NULL) && lEndPoint->IsCreatedByInetLayer(*this))
-            lEndPoint->PrepareIO().SetFDs(lEndPoint->mSocket, nfds, readfds, writefds, exceptfds);
+            lEndPoint->PrepareIO().SetFDs(lEndPoint->mSocket, pollFDs, numPollFDs);
     }
 #endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
 
@@ -1461,14 +1453,14 @@
     {
         TunEndPoint* lEndPoint = TunEndPoint::sPool.Get(*mSystemLayer, i);
         if ((lEndPoint != NULL) && lEndPoint->IsCreatedByInetLayer(*this))
-            lEndPoint->PrepareIO().SetFDs(lEndPoint->mSocket, nfds, readfds, writefds, exceptfds);
+            lEndPoint->PrepareIO().SetFDs(lEndPoint->mSocket, pollFDs, numPollFDs);
     }
 #endif // INET_CONFIG_ENABLE_TUN_ENDPOINT
 
 #if INET_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
     if (mSystemLayer == &mImplicitSystemLayer)
     {
-        mSystemLayer->PrepareSelect(nfds, readfds, writefds, exceptfds, sleepTimeTV);
+        mSystemLayer->PrepareSelect(pollFDs, numPollFDs, timeoutMS);
     }
 #endif // INET_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
 }
@@ -1490,26 +1482,14 @@
  *    on it allows the endpoint code to clear the I/O flags in the event
  *    of a close, thus avoiding any confusion.
  *
- *  @param[in]    selectRes    The return value of the select call.
- *
- *  @param[in]    readfds      A pointer to the set of read file descriptors.
- *
- *  @param[in]    writefds     A pointer to the set of write file descriptors.
- *
- *  @param[in]    exceptfds    A pointer to the set of file descriptors with
- *                             errors.
- *
+ *  @param[in]  pollFDs     The result of polled FDs
+ *  @param[in]  numPollFDs  The number of fds in the fd set
  */
-void InetLayer::HandleSelectResult(int selectRes, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
+void InetLayer::HandleSelectResult(const struct pollfd * pollFDs, int numPollFDs)
 {
     if (State != kState_Initialized)
         return;
 
-    if (selectRes < 0)
-        return;
-
-    if (selectRes > 0)
-    {
         // Set the pending I/O field for each active endpoint based on the value returned by select.
 #if INET_CONFIG_ENABLE_RAW_ENDPOINT
         for (size_t i = 0; i < RawEndPoint::sPool.Size(); i++)
@@ -1517,7 +1497,7 @@
             RawEndPoint* lEndPoint = RawEndPoint::sPool.Get(*mSystemLayer, i);
             if ((lEndPoint != NULL) && lEndPoint->IsCreatedByInetLayer(*this))
             {
-                lEndPoint->mPendingIO = SocketEvents::FromFDs(lEndPoint->mSocket, readfds, writefds, exceptfds);
+                lEndPoint->mPendingIO = SocketEvents::FromFDs(lEndPoint->mSocket, pollFDs, numPollFDs);
             }
         }
 #endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
@@ -1528,7 +1508,7 @@
             TCPEndPoint* lEndPoint = TCPEndPoint::sPool.Get(*mSystemLayer, i);
             if ((lEndPoint != NULL) && lEndPoint->IsCreatedByInetLayer(*this))
             {
-                lEndPoint->mPendingIO = SocketEvents::FromFDs(lEndPoint->mSocket, readfds, writefds, exceptfds);
+                lEndPoint->mPendingIO = SocketEvents::FromFDs(lEndPoint->mSocket, pollFDs, numPollFDs);
             }
         }
 #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
@@ -1539,7 +1519,7 @@
             UDPEndPoint* lEndPoint = UDPEndPoint::sPool.Get(*mSystemLayer, i);
             if ((lEndPoint != NULL) && lEndPoint->IsCreatedByInetLayer(*this))
             {
-                lEndPoint->mPendingIO = SocketEvents::FromFDs(lEndPoint->mSocket, readfds, writefds, exceptfds);
+                lEndPoint->mPendingIO = SocketEvents::FromFDs(lEndPoint->mSocket, pollFDs, numPollFDs);
             }
         }
 #endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
@@ -1550,7 +1530,7 @@
             TunEndPoint* lEndPoint = TunEndPoint::sPool.Get(*mSystemLayer, i);
             if ((lEndPoint != NULL) && lEndPoint->IsCreatedByInetLayer(*this))
             {
-                lEndPoint->mPendingIO = SocketEvents::FromFDs(lEndPoint->mSocket, readfds, writefds, exceptfds);
+                lEndPoint->mPendingIO = SocketEvents::FromFDs(lEndPoint->mSocket, pollFDs, numPollFDs);
             }
         }
 #endif // INET_CONFIG_ENABLE_TUN_ENDPOINT
@@ -1599,12 +1579,11 @@
             }
         }
 #endif // INET_CONFIG_ENABLE_TUN_ENDPOINT
-    }
 
 #if INET_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
     if (mSystemLayer == &mImplicitSystemLayer)
     {
-        mSystemLayer->HandleSelectResult(selectRes, readfds, writefds, exceptfds);
+        mSystemLayer->HandleSelectResult(pollFDs, numPollFDs);
     }
 #endif // INET_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
 }
diff --git a/src/inet/InetLayer.h b/src/inet/InetLayer.h
index 678e997..a4e8ddd 100644
--- a/src/inet/InetLayer.h
+++ b/src/inet/InetLayer.h
@@ -284,8 +284,8 @@
 #endif // INET_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-    void PrepareSelect(int& nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval& sleepTime);
-    void HandleSelectResult(int selectRes, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
+    void PrepareSelect(struct pollfd * pollFDs, int& numPollFDs, int& timeoutMS);
+    void HandleSelectResult(const struct pollfd * pollFDs, int numPollFDs);
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
     static void UpdateSnapshot(nl::Weave::System::Stats::Snapshot &aSnapshot);
diff --git a/src/inet/InetLayerBasis.cpp b/src/inet/InetLayerBasis.cpp
index 8db5fc2..3895fc0 100644
--- a/src/inet/InetLayerBasis.cpp
+++ b/src/inet/InetLayerBasis.cpp
@@ -32,29 +32,24 @@
 /**
  *  Sets the bit for the specified file descriptor in the given sets of file descriptors.
  *
- *  @param[in]    socket    The file descriptor for which the bit is being set.
- *
- *  @param[out]   nfds      A reference to the range of file descriptors in the set.
- *
- *  @param[in]    readfds   A pointer to the set of readable file descriptors.
- *
- *  @param[in]    writefds  A pointer to the set of writable file descriptors.
- *
- *  @param[in]    exceptfds  A pointer to the set of file descriptors with errors.
- *
+ *  @param[in]      socket      The file descriptor for which the bit is being set.
+ *  @param[in,out]  pollFDs     The fd set which is going to be polled
+ *  @param[in,out]  numPollFDs  The number of fds in the fd set
  */
-void SocketEvents::SetFDs(int socket, int& nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
+void SocketEvents::SetFDs(int socket, struct pollfd * pollFDs, int& numPollFDs)
 {
     if (socket != INET_INVALID_SOCKET_FD)
     {
+        struct pollfd & event = pollFDs[numPollFDs];
+        event.fd = socket;
+        event.events = 0;
+        event.revents = 0;
         if (IsReadable())
-            FD_SET(socket, readfds);
+            event.events |= POLLIN;
         if (IsWriteable())
-            FD_SET(socket, writefds);
-        if (IsError())
-            FD_SET(socket, exceptfds);
-        if (IsSet() && (socket + 1) > nfds)
-            nfds = socket + 1;
+            event.events |= POLLOUT;
+        if (event.events != 0)
+            numPollFDs++;
     }
 }
 
@@ -62,27 +57,29 @@
  *  Set the read, write or exception bit flags for the specified socket based on its status in
  *  the corresponding file descriptor sets.
  *
- *  @param[in]    socket    The file descriptor for which the bit flags are being set.
- *
- *  @param[in]    readfds   A pointer to the set of readable file descriptors.
- *
- *  @param[in]    writefds  A pointer to the set of writable file descriptors.
- *
- *  @param[in]    exceptfds  A pointer to the set of file descriptors with errors.
- *
+ *  @param[in]    socket      The file descriptor for which the bit flags are being set.
+ *  @param[in]    pollFDs     The result of polled FDs
+ *  @param[in]    numPollFDs  The number of fds in the fd set
  */
-SocketEvents SocketEvents::FromFDs(int socket, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
+SocketEvents SocketEvents::FromFDs(int socket, const struct pollfd * pollFDs, int numPollFDs)
 {
     SocketEvents res;
 
     if (socket != INET_INVALID_SOCKET_FD)
     {
-        if (FD_ISSET(socket, readfds))
-            res.SetRead();
-        if (FD_ISSET(socket, writefds))
-            res.SetWrite();
-        if (FD_ISSET(socket, exceptfds))
-            res.SetError();
+        for (int i = 0; i < numPollFDs; ++i)
+        {
+            const struct pollfd & event = pollFDs[i];
+            if (event.fd == socket)
+            {
+                if ((event.revents & (POLLIN | POLLHUP)) != 0)
+                    res.SetRead();
+                if ((event.revents & POLLOUT) != 0)
+                    res.SetWrite();
+                if ((event.revents & POLLERR) != 0)
+                    res.SetError();
+            }
+        }
     }
 
     return res;
diff --git a/src/inet/InetLayerBasis.h b/src/inet/InetLayerBasis.h
index 297e30f..fa2c6ba 100644
--- a/src/inet/InetLayerBasis.h
+++ b/src/inet/InetLayerBasis.h
@@ -33,7 +33,7 @@
 #include <stdint.h>
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-#include <sys/select.h>
+#include <poll.h>
 #endif
 
 namespace nl {
@@ -204,8 +204,8 @@
      */
     void ClearError()           { Value &= ~kError; }
 
-    void SetFDs(int socket, int& nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
-    static SocketEvents FromFDs(int socket, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
+    void SetFDs(int socket, struct pollfd * pollFDs, int& numPollFDs);
+    static SocketEvents FromFDs(int socket, const struct pollfd * pollFDs, int numPollFDs);
 };
 
 /**
diff --git a/src/inet/RawEndPoint.cpp b/src/inet/RawEndPoint.cpp
index c53a504..2c0def5 100644
--- a/src/inet/RawEndPoint.cpp
+++ b/src/inet/RawEndPoint.cpp
@@ -46,7 +46,7 @@
 #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-#include <sys/select.h>
+#include <poll.h>
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif // HAVE_SYS_SOCKET_H
diff --git a/src/inet/TCPEndPoint.cpp b/src/inet/TCPEndPoint.cpp
index 3ac8722..61cab5f 100644
--- a/src/inet/TCPEndPoint.cpp
+++ b/src/inet/TCPEndPoint.cpp
@@ -51,7 +51,7 @@
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 #include <sys/socket.h>
-#include <sys/select.h>
+#include <poll.h>
 #include <net/if.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
diff --git a/src/inet/UDPEndPoint.cpp b/src/inet/UDPEndPoint.cpp
index 432aa18..d741842 100644
--- a/src/inet/UDPEndPoint.cpp
+++ b/src/inet/UDPEndPoint.cpp
@@ -46,7 +46,7 @@
 #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-#include <sys/select.h>
+#include <poll.h>
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif // HAVE_SYS_SOCKET_H
diff --git a/src/lib/core/ExchangeContext.cpp b/src/lib/core/ExchangeContext.cpp
index 8cb0299..08abd02 100644
--- a/src/lib/core/ExchangeContext.cpp
+++ b/src/lib/core/ExchangeContext.cpp
@@ -66,6 +66,7 @@
     kFlagAutoReleaseKey         = 0x0100, /// Automatically release the message encryption key when the exchange context is freed.
     kFlagAutoReleaseConnection  = 0x0200, /// Automatically release the associated WeaveConnection when the exchange context is freed.
     kFlagUseEphemeralUDPPort    = 0x0400, /// When set, use the local ephemeral UDP port as the source port for outbound messages.
+    kFlagCaptureSentMessage     = 0x0800, /// Capture the sent message after encoded with Weave headers.
 };
 
 /**
@@ -314,6 +315,18 @@
     SetFlag(mFlags, static_cast<uint16_t>(kFlagAutoReleaseConnection), autoReleaseCon);
 }
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+void ExchangeContext::SetCaptureSentMessage(bool inCaptureSentMessage)
+{
+    SetFlag(mFlags, static_cast<uint16_t>(kFlagCaptureSentMessage), inCaptureSentMessage);
+}
+
+bool ExchangeContext::ShouldCaptureSentMessage() const
+{
+    return GetFlag(mFlags, static_cast<uint16_t>(kFlagCaptureSentMessage));
+}
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
 /**
  * @fn  bool ExchangeContext::UseEphemeralUDPPort(void) const
  *
@@ -563,6 +576,15 @@
     SetFlag(msgInfo->Flags, kWeaveMessageFlag_ViaEphemeralUDPPort, UseEphemeralUDPPort());
 #endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    // Set flag for capture in MessageInfo if ExchangeContext is marked for
+    // capture.
+    if (ShouldCaptureSentMessage())
+    {
+        msgInfo->Flags |= kWeaveMessageFlag_CaptureTxMessage;
+    }
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     // Send the message via UDP or TCP/BLE based on the presence of a connection.
     if (Con != NULL)
     {
diff --git a/src/lib/core/HostPortList.cpp b/src/lib/core/HostPortList.cpp
index 5cbbcb9..41191d6 100644
--- a/src/lib/core/HostPortList.cpp
+++ b/src/lib/core/HostPortList.cpp
@@ -35,15 +35,6 @@
 using namespace nl::Weave::Encoding;
 
 /**
- *  Class default (void) constructor.
- *
- */
-HostPortList::HostPortList(void)
-{
-    Clear();
-}
-
-/**
  *  Reset the list to empty.
  *
  */
diff --git a/src/lib/core/HostPortList.h b/src/lib/core/HostPortList.h
index 7151b54..42cf120 100644
--- a/src/lib/core/HostPortList.h
+++ b/src/lib/core/HostPortList.h
@@ -46,7 +46,7 @@
 class HostPortList
 {
  public:
-    HostPortList(void);
+    HostPortList(void) = default;
     inline HostPortList(const uint8_t *hostPortList, uint8_t hostPortCount, const uint8_t *suffixList, const uint8_t suffixCount)
     {
         mElements    = hostPortList;
diff --git a/src/lib/core/WeaveBinding.cpp b/src/lib/core/WeaveBinding.cpp
index 87c0629..01079c5 100644
--- a/src/lib/core/WeaveBinding.cpp
+++ b/src/lib/core/WeaveBinding.cpp
@@ -1374,6 +1374,14 @@
         appExchangeContext->SetAutoReleaseKey(true);
     }
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    // If message is marked for capture set flag in Exchange Context
+    if (GetFlag(kFlag_CaptureTxMessage))
+    {
+        appExchangeContext->SetCaptureSentMessage(true);
+    }
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     err = AdjustResponseTimeout(appExchangeContext);
     SuccessOrExit(err);
 
@@ -1930,6 +1938,19 @@
     return *this;
 }
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+/**
+ *  Set the flag for capturing sent messages
+ *
+ *  @return                     A reference to the Binding object.
+ */
+Binding::Configuration& Binding::Configuration::CaptureTxMessage(void)
+{
+    mBinding.SetFlag(kFlag_CaptureTxMessage);
+    return *this;
+}
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
 /**
  *  Configure the binding to allow communication with the sender of a received message.
  *
diff --git a/src/lib/core/WeaveBinding.h b/src/lib/core/WeaveBinding.h
index 0d78186..1c12e2b 100644
--- a/src/lib/core/WeaveBinding.h
+++ b/src/lib/core/WeaveBinding.h
@@ -268,6 +268,7 @@
     {
         kFlag_KeyReserved                           = 0x1,
         kFlag_ConnectionReferenced                  = 0x2,
+        kFlag_CaptureTxMessage                      = 0x4,
     };
 
     WeaveExchangeManager * mExchangeManager;
@@ -389,6 +390,10 @@
     Configuration& Security_EncryptionType(uint8_t aEncType);
     Configuration& Security_AuthenticationMode(WeaveAuthMode aAuthMode);
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    Configuration& CaptureTxMessage(void);
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     Configuration& ConfigureFromMessage(const WeaveMessageInfo *aMsgInfo, const Inet::IPPacketInfo *aPacketInfo);
 
     WEAVE_ERROR PrepareBinding(void);
diff --git a/src/lib/core/WeaveConfig.h b/src/lib/core/WeaveConfig.h
index acf5067..3bd4d2a 100644
--- a/src/lib/core/WeaveConfig.h
+++ b/src/lib/core/WeaveConfig.h
@@ -2403,6 +2403,22 @@
 #endif // WEAVE_CONFIG_TCP_CONN_REPAIR_SUPPORTED
 
 /**
+ * @def WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+ *
+ * @brief
+ *   When this option is enabled, transmitted Weave messages can be captured
+ *   back at the WeaveMessageLayer after being fully encoded with the Weave
+ *   Exchange and Message layer headers.
+ *   In orderr to capture messages, the application can configure a WeaveBinding
+ *   object to vend an ExchangeContext that is tagged for capture. Thereafter,
+ *   all transmitted messages on that ExchangeContext would be captured.
+ *
+ */
+#ifndef WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+#define WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE                 0
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
+/**
  * @def WEAVE_NON_PRODUCTION_MARKER
  *
  * @brief Defines the name of a mark symbol whose presence signals that the Weave code
@@ -2422,6 +2438,15 @@
 extern const char WEAVE_NON_PRODUCTION_MARKER[];
 #endif
 
+/**
+ * @def WEAVE_CONFIG_MAX_POLL_FDS
+ *
+ * @brief Max number of select/poll fds.
+ */
+#ifndef WEAVE_CONFIG_MAX_POLL_FDS
+#define WEAVE_CONFIG_MAX_POLL_FDS 16
+#endif // WEAVE_CONFIG_MAX_POLL_FDS
+
 // clang-format on
 
 #endif /* WEAVE_CONFIG_H_ */
diff --git a/src/lib/core/WeaveConnection.cpp b/src/lib/core/WeaveConnection.cpp
index be05b1c..7ffd9c6 100644
--- a/src/lib/core/WeaveConnection.cpp
+++ b/src/lib/core/WeaveConnection.cpp
@@ -661,6 +661,7 @@
     {
         msgInfo->Flags |= kWeaveMessageFlag_DestNodeId;
     }
+
     // Encode the Weave message. NOTE that this results in the payload buffer containing the entire encoded message.
     // If the encoded message would have exceeded the sent limit, return WEAVE_ERROR_SENDING_BLOCKED to the caller.
     res = MessageLayer->EncodeMessageWithLength(msgInfo, msgBuf, this, UINT16_MAX);
@@ -672,6 +673,18 @@
     // Copy msg to a right-sized buffer if applicable
     msgBuf = PacketBuffer::RightSize(msgBuf);
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    if (GetFlag(msgInfo->Flags, kWeaveMessageFlag_CaptureTxMessage))
+    {
+        WeaveLogDetail(MessageLayer, "Message tagged for capture over Con  %04X ", LogId());
+        if (MessageLayer->OnMessageCapture)
+        {
+            MessageLayer->OnMessageCapture(msgBuf->Start(), msgBuf->DataLength(), msgInfo);
+        }
+        ExitNow(res);
+    }
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
 #if CONFIG_NETWORK_LAYER_BLE
     if (mBleEndPoint != NULL)
     {
@@ -1117,7 +1130,8 @@
             MessageLayer->ExchangeMgr->HandleConnectionClosed(this, err);
 
         // Call the Fabric state object to alert it of the connection close.
-        MessageLayer->FabricState->HandleConnectionClosed(this);
+        if (MessageLayer->FabricState != NULL)
+            MessageLayer->FabricState->HandleConnectionClosed(this);
 
         // Call the appropriate app callback if allowed.
         if ((flags & kDoCloseFlag_SuppressCallback) == 0)
diff --git a/src/lib/core/WeaveExchangeMgr.cpp b/src/lib/core/WeaveExchangeMgr.cpp
index 845861b..dba2c36 100644
--- a/src/lib/core/WeaveExchangeMgr.cpp
+++ b/src/lib/core/WeaveExchangeMgr.cpp
@@ -666,7 +666,7 @@
 
     WeaveLogRetain(ExchangeManager, "Msg %s %08" PRIX32 ":%d %d %016" PRIX64 " %04" PRIX16 " %04" PRIX16 " %ld MsgId:%08" PRIX32,
                    "rcvd", exchangeHeader.ProfileId, exchangeHeader.MessageType,
-                   (int)msgBuf->DataLength(), msgInfo->SourceNodeId, msgCon->LogId(), exchangeHeader.ExchangeId,
+                   (int)msgBuf->DataLength(), msgInfo->SourceNodeId, ((msgCon == NULL) ? -1 : msgCon->LogId()), exchangeHeader.ExchangeId,
                    (long)err, msgInfo->MessageId);
 
 #if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
@@ -1556,7 +1556,7 @@
 WEAVE_ERROR WeaveExchangeManager::SendFromRetransTable(RetransTableEntry *entry)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
-    uint16_t msgSendFlags = 0;
+    uint32_t msgSendFlags = 0;
     uint8_t     *p = NULL;
     uint32_t    len = 0;
     ExchangeContext *ec = entry->exchContext;
@@ -1573,6 +1573,12 @@
 
     if (ec)
     {
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+        if (ec->ShouldCaptureSentMessage())
+        {
+            SetFlag(msgSendFlags, kWeaveMessageFlag_CaptureTxMessage);
+        }
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
         SetFlag(msgSendFlags, kWeaveMessageFlag_RetainBuffer);
 
 #if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
diff --git a/src/lib/core/WeaveExchangeMgr.h b/src/lib/core/WeaveExchangeMgr.h
index 957d6c0..fb638a8 100644
--- a/src/lib/core/WeaveExchangeMgr.h
+++ b/src/lib/core/WeaveExchangeMgr.h
@@ -159,6 +159,8 @@
         kSendFlag_RequestAck                    = 0x0400, /**< Used to send a WRM message requesting an acknowledgment. */
         kSendFlag_NoAutoRequestAck              = 0x0800, /**< Suppress the auto-request acknowledgment feature when sending a message. */
 
+        kSendFlag_CaptureSentMessage            = 0x1000, /**< Capture the sent message after encoded with Weave headers */
+
         kSendFlag_MulticastFromLinkLocal        = kSendFlag_DefaultMulticastSourceAddress,
                                                           /**< Deprecated alias for \c kSendFlag_DefaultMulticastSourceAddress */
     };
@@ -192,6 +194,11 @@
     void SetUseEphemeralUDPPort(bool val);
 #endif
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    void SetCaptureSentMessage(bool inCaptureSentMessage);
+    bool ShouldCaptureSentMessage() const;
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     WEAVE_ERROR SendMessage(uint32_t profileId, uint8_t msgType, PacketBuffer *msgPayload, uint16_t sendFlags = 0, void *msgCtxt = 0);
     WEAVE_ERROR SendMessage(uint32_t profileId, uint8_t msgType, PacketBuffer *msgBuf, uint16_t sendFlags, WeaveMessageInfo * msgInfo, void *msgCtxt = 0);
     WEAVE_ERROR SendCommonNullMessage(void);
diff --git a/src/lib/core/WeaveMessageLayer.cpp b/src/lib/core/WeaveMessageLayer.cpp
index 5393077..a7b9717 100644
--- a/src/lib/core/WeaveMessageLayer.cpp
+++ b/src/lib/core/WeaveMessageLayer.cpp
@@ -153,6 +153,9 @@
     SecurityMgr = NULL;
     IsListening = context->listenTCP || context->listenUDP;
     IncomingConIdleTimeout = WEAVE_CONFIG_DEFAULT_INCOMING_CONNECTION_IDLE_TIMEOUT;
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    OnMessageCapture = NULL;
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
 
     //Internal and for Debug Only; When set, Message Layer drops message and returns.
     mDropMessage = false;
@@ -250,6 +253,9 @@
     ExchangeMgr = NULL;
     AppState = NULL;
     mFlags = 0;
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    OnMessageCapture = NULL;
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
 
     return WEAVE_NO_ERROR;
 }
@@ -547,7 +553,7 @@
  *  @retval  errors generated from the lower Inet layer UDP endpoint during sending.
  *
  */
-WEAVE_ERROR WeaveMessageLayer::SendMessage(const IPAddress & destAddr, uint16_t destPort, InterfaceId sendIntfId,
+WEAVE_ERROR WeaveMessageLayer::SendMessage(IPAddress & destAddr, uint16_t destPort, InterfaceId sendIntfId,
                                            PacketBuffer * payload, uint32_t msgFlags)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
@@ -561,6 +567,21 @@
     } sendAction;
     uint16_t udpSendFlags;
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    // Check the destination address to check if the message is meant to be sent
+    // to the Service Cloud subnet. In that case, replace the subnetID to the
+    // CaptureSubnet if it is tagged for capture.
+
+    if (GetFlag(msgFlags, kWeaveMessageFlag_CaptureTxMessage) && destAddr.Subnet() == kWeaveSubnetId_Service)
+    {
+        char ipAddrStr[64];
+        destAddr = IPAddress::MakeULA(FabricState->FabricId, kWeaveSubnetId_TunneledCapture, destAddr.InterfaceId());
+        ClearFlag(msgFlags, kWeaveMessageFlag_CaptureTxMessage);
+        destAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
+        WeaveLogDetail(ExchangeManager, "Setting Capture Subnet in DestAddr %s", ipAddrStr);
+    }
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     IPPacketInfo pktInfo;
     pktInfo.Clear();
     pktInfo.DestAddress = destAddr;
@@ -625,6 +646,23 @@
         sendAction = kMulticast_AllInterfaces;
     }
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    // Capture the message if it is tagged for capture in the message flags
+    if (GetFlag(msgFlags, kWeaveMessageFlag_CaptureTxMessage))
+    {
+        WeaveMessageInfo msgInfo;
+        memset(&msgInfo, 0, sizeof(msgInfo));
+        msgInfo.Flags = msgFlags;
+
+        if (OnMessageCapture)
+        {
+            OnMessageCapture(payload->Start(), payload->DataLength(), &msgInfo);
+        }
+
+        ExitNow(err);
+    }
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     // Send the message...
     switch (sendAction)
     {
@@ -645,7 +683,10 @@
         // Send the message over each local interface that supports multicast.
         for (InterfaceIterator intfIter; intfIter.HasCurrent(); intfIter.Next())
         {
-            if (intfIter.SupportsMulticast())
+            bool isBroadcastSupported = intfIter.SupportsMulticast() &&
+                intfIter.HasBroadcastAddress() &&
+                intfIter.IsUp();
+            if (isBroadcastSupported)
             {
                 pktInfo.Interface = intfIter.GetInterface();
                 WEAVE_ERROR sendErr = ep->SendMsg(&pktInfo, payload, UDPEndPoint::kSendFlag_RetainBuffer);
@@ -668,7 +709,10 @@
         {
             pktInfo.SrcAddress = addrIter.GetAddress();
             pktInfo.Interface = addrIter.GetInterface();
-            if (addrIter.SupportsMulticast() &&
+            bool isBroadcastSupported = addrIter.SupportsMulticast() &&
+                addrIter.HasBroadcastAddress() &&
+                addrIter.IsUp();
+            if (isBroadcastSupported &&
                 FabricState->IsLocalFabricAddress(pktInfo.SrcAddress) &&
                 (sendIntfId == INET_NULL_INTERFACEID || pktInfo.Interface == sendIntfId))
             {
@@ -2406,6 +2450,22 @@
     OnMessageLayerActivityChange = messageLayerActivityChangeHandler;
 }
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+/**
+ *  Set an application handler that would get called to receive the captured
+ *  message.
+ *
+ *  @param[in] messageLayerPktCaptureHandler A pointer to a function to be
+ *             called when a message is captured by the WeaveMessageLayer.
+ *
+ *  @retval None.
+ */
+void WeaveMessageLayer::SetMessageLayerPktCaptureHandler(MessageLayerPktCaptureHandlerFunct messageLayerPktCaptureHandler)
+{
+    OnMessageCapture = messageLayerPktCaptureHandler;
+}
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
 bool WeaveMessageLayer::IsMessageLayerActive(void)
 {
     return (ExchangeMgr->mContextsInUse != 0)
diff --git a/src/lib/core/WeaveMessageLayer.h b/src/lib/core/WeaveMessageLayer.h
index 44cb6c1..1bf664f 100644
--- a/src/lib/core/WeaveMessageLayer.h
+++ b/src/lib/core/WeaveMessageLayer.h
@@ -137,10 +137,11 @@
     kWeaveMessageFlag_PeerRequestedAck                  = 0x00004000, /**< Indicates that the sender of the  message requested an acknowledgment. */
     kWeaveMessageFlag_DuplicateMessage                  = 0x00008000, /**< Indicates that the message is a duplicate of a previously received message. */
     kWeaveMessageFlag_PeerGroupMsgIdNotSynchronized     = 0x00010000, /**< Indicates that the peer's group key message counter is not synchronized. */
-	kWeaveMessageFlag_FromInitiator                     = 0x00020000, /**< Indicates that the source of the message is the initiator of the
-																		   Weave exchange. */
+    kWeaveMessageFlag_FromInitiator                     = 0x00020000, /**< Indicates that the source of the message is the initiator of the Weave exchange. */
     kWeaveMessageFlag_ViaEphemeralUDPPort               = 0x00040000, /**< Indicates that message is being sent/received via the local ephemeral UDP port. */
 
+    kWeaveMessageFlag_CaptureTxMessage                  = 0x00080000, /**< Indicates that the outgoing message needs to be captured. */
+
     kWeaveMessageFlag_MulticastFromLinkLocal            = kWeaveMessageFlag_DefaultMulticastSourceAddress,
                                                                       /**< Deprecated alias for \c kWeaveMessageFlag_DefaultMulticastSourceAddress */
 
@@ -745,6 +746,27 @@
     void SetSignalMessageLayerActivityChanged(MessageLayerActivityChangeHandlerFunct messageLayerActivityChangeHandler);
     bool IsMessageLayerActive(void);
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    /**
+     *  This function is the callback for capturing a sent Weave message and
+     *  passing it to the application. The Weave message encoded all the way to
+     *  the MessageLayer is captured and handed over via this API.
+     *
+     *  @param[in] msgBuf   A pointer to the Weave message being captured.
+     *
+     *  @param[in] msgLen   Length of the encoded message in the buffer.
+     *
+     *  @param[in] msgInfo  A pointer to the WeaveMessageInfo object
+     *                      pertaining to this captured message.
+     *
+     *  @note
+     *    All pointer parameters passed via this API may be freed once the callback returns and it is the responsibility
+     *    of the callee to copy their contents if need be.
+     */
+    typedef void (*MessageLayerPktCaptureHandlerFunct)(uint8_t *msgBuf, uint16_t msgLen, WeaveMessageInfo *msgInfo);
+    void SetMessageLayerPktCaptureHandler(MessageLayerPktCaptureHandlerFunct messageLayerPktCaptureHandler);
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     static uint32_t GetMaxWeavePayloadSize(const PacketBuffer *msgBuf, bool isUDP, uint32_t udpMTU);
 
     static void GetPeerDescription(char *buf, size_t bufSize, uint64_t nodeId, const IPAddress *addr, uint16_t port, InterfaceId interfaceId, const WeaveConnection *con);
@@ -795,6 +817,10 @@
     void *UnsecuredConnectionReceivedAppState;
     MessageLayerActivityChangeHandlerFunct OnMessageLayerActivityChange;
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    MessageLayerPktCaptureHandlerFunct OnMessageCapture;
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     WEAVE_ERROR EnableUnsecuredListen(void);
     WEAVE_ERROR DisableUnsecuredListen(void);
 
@@ -805,7 +831,7 @@
     WEAVE_ERROR RefreshEndpoint(TCPEndPoint *& endPoint, bool enable, const char * name, IPAddressType addrType, IPAddress addr, uint16_t port);
     WEAVE_ERROR RefreshEndpoint(UDPEndPoint *& endPoint, bool enable, const char * name, IPAddressType addrType, IPAddress addr, uint16_t port, InterfaceId intfId);
 
-    WEAVE_ERROR SendMessage(const IPAddress &destAddr, uint16_t destPort, InterfaceId sendIntfId, PacketBuffer *payload, uint32_t msgFlags);
+    WEAVE_ERROR SendMessage(IPAddress &destAddr, uint16_t destPort, InterfaceId sendIntfId, PacketBuffer *payload, uint32_t msgFlags);
     WEAVE_ERROR SelectOutboundUDPEndPoint(const IPAddress & destAddr, uint32_t msgFlags, UDPEndPoint *& ep);
     WEAVE_ERROR SelectDestNodeIdAndAddress(uint64_t& destNodeId, IPAddress& destAddr);
     WEAVE_ERROR DecodeMessage(PacketBuffer *msgBuf, uint64_t sourceNodeId, WeaveConnection *con,
@@ -1086,6 +1112,7 @@
     kWeaveSubnetId_MobileDevice                         = 4, /**< The subnet identifier for all Mobile devices. */
     kWeaveSubnetId_Service                              = 5, /**< The subnet identifier for the Nest Service endpoints. */
     kWeaveSubnetId_ThreadMesh                           = 6, /**< The Thread mesh radio interface subnet identifier. */
+    kWeaveSubnetId_TunneledCapture                      = 32, /**< A Subnet identifier for marking a tunneled packet for capture. */
 } WeaveSubnetId;
 
 #define WEAVE_MAX_NODE_ADDR_STR_LENGTH (nl::Weave::kWeavePeerDescription_MaxLength)
diff --git a/src/lib/core/WeaveTLVDebug.cpp b/src/lib/core/WeaveTLVDebug.cpp
index bd66a7d..8d6cf46 100644
--- a/src/lib/core/WeaveTLVDebug.cpp
+++ b/src/lib/core/WeaveTLVDebug.cpp
@@ -154,7 +154,10 @@
                 err = temp.GetDataPtr(strbuf);
                 VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_ByteString"));
             }
-            aWriter("%p\n", strbuf);
+            for (int i = 0; i < len; i++) {
+              aWriter("%02x ", strbuf[i]);
+            }
+            aWriter("\n");
             break;
 
         case kTLVType_Null:
diff --git a/src/lib/core/WeaveTLVReader.cpp b/src/lib/core/WeaveTLVReader.cpp
index ae48bf9..e6e198b 100644
--- a/src/lib/core/WeaveTLVReader.cpp
+++ b/src/lib/core/WeaveTLVReader.cpp
@@ -541,6 +541,45 @@
     return WEAVE_NO_ERROR;
 }
 
+namespace {
+float BitCastToFloat(const uint64_t elemLenOrVal)
+{
+    float f;
+    auto u32 = static_cast<uint32_t>(elemLenOrVal);
+    memcpy(&f, &u32, sizeof(f));
+    return f;
+}
+} // namespace
+
+// Note: Unlike the integer Get functions, this code avoids doing conversions
+// between float and double wherever possible, because these conversions are
+// relatively expensive on platforms that use soft-float instruction sets.
+
+/**
+ * Get the value of the current element as a single-precision floating point number.
+ *
+ * @param[out]  v                       Receives the value associated with current TLV element.
+ *
+ * @retval #WEAVE_NO_ERROR              If the method succeeded.
+ * @retval #WEAVE_ERROR_WRONG_TLV_TYPE  If the current element is not a TLV floating point type, or
+ *                                      the reader is not positioned on an element.
+ *
+ */
+WEAVE_ERROR TLVReader::Get(float & v)
+{
+    switch (ElementType())
+    {
+    case kTLVElementType_FloatingPointNumber32:
+    {
+        v = BitCastToFloat(mElemLenOrVal);
+        break;
+    }
+    default:
+        return WEAVE_ERROR_WRONG_TLV_TYPE;
+    }
+    return WEAVE_NO_ERROR;
+}
+
 /**
  * Get the value of the current element as a double-precision floating point number.
  *
@@ -557,24 +596,14 @@
     {
     case kTLVElementType_FloatingPointNumber32:
     {
-        union
-        {
-            uint32_t u32;
-            float f;
-        } cvt;
-        cvt.u32 = (uint32_t)mElemLenOrVal;
-        v = cvt.f;
+        v = BitCastToFloat(mElemLenOrVal);
         break;
     }
     case kTLVElementType_FloatingPointNumber64:
     {
-        union
-        {
-            uint64_t u64;
-            double d;
-        } cvt;
-        cvt.u64 = mElemLenOrVal;
-        v = cvt.d;
+        double d;
+        memcpy(&d, &mElemLenOrVal, sizeof(d));
+        v = d;
         break;
     }
     default:
diff --git a/src/lib/profiles/data-management/Current/Command.h b/src/lib/profiles/data-management/Current/Command.h
index 6cb07b7..58155fd 100644
--- a/src/lib/profiles/data-management/Current/Command.h
+++ b/src/lib/profiles/data-management/Current/Command.h
@@ -77,18 +77,6 @@
 class NL_DLL_EXPORT Command
 {
 public:
-    /**
-     *  @brief
-     *    The Command flag bits.
-     */
-    typedef enum CommandFlags
-    {
-        kCommandFlag_MustBeVersionValid   = 0x0001,  /**< Set when the version field is valid */
-        kCommandFlag_InitiationTimeValid  = 0x0002,  /**< Set when the init time is valid */
-        kCommandFlag_ActionTimeValid      = 0x0004,  /**< Set when the action time is valid */
-        kCommandFlag_ExpiryTimeValid      = 0x0008,  /**< Set when the expiry time is valid */
-        kCommandFlag_IsOneWay             = 0x0010,  /**< Set when the command is one-way */
-    } CommandFlags;
 
     uint64_t commandType;
     uint64_t mustBeVersion;
diff --git a/src/lib/profiles/data-management/Current/CommandSender.cpp b/src/lib/profiles/data-management/Current/CommandSender.cpp
index a5e9f39..27c3bf8 100644
--- a/src/lib/profiles/data-management/Current/CommandSender.cpp
+++ b/src/lib/profiles/data-management/Current/CommandSender.cpp
@@ -209,9 +209,7 @@
 
 WEAVE_ERROR CommandSender::SendCommand(nl::Weave::PacketBuffer *aPayload, nl::Weave::Binding *aBinding, ResourceIdentifier &aResourceId, uint32_t aProfileId, uint32_t aCommandType)
 {
-    SendParams sendParams;
-
-    memset(&sendParams, 0, sizeof(sendParams));
+    SendParams sendParams = SendParams();
 
     sendParams.ResourceId = aResourceId;
     sendParams.ProfileId = aProfileId;
@@ -431,12 +429,11 @@
 
 void CommandSender::OnResponseTimeout(ExchangeContext *aEC)
 {
-    WEAVE_ERROR err = WEAVE_NO_ERROR;
     CommandSender *_this = static_cast<CommandSender *>(aEC->AppState);
     InEventParam inEventParam;
     OutEventParam outEventParam;
 
-    VerifyOrExit(_this, err = WEAVE_ERROR_INVALID_ARGUMENT);
+    VerifyOrExit(_this, );
 
     inEventParam.CommunicationError.error = WEAVE_ERROR_TIMEOUT;
     _this->mEventCallback(_this->mAppState, kEvent_CommunicationError, inEventParam, outEventParam);
diff --git a/src/lib/profiles/data-management/Current/LoggingManagement.cpp b/src/lib/profiles/data-management/Current/LoggingManagement.cpp
index ff32a7a..df2f09a 100644
--- a/src/lib/profiles/data-management/Current/LoggingManagement.cpp
+++ b/src/lib/profiles/data-management/Current/LoggingManagement.cpp
@@ -2276,9 +2276,9 @@
     size_t bufLen = mBuffer.GetQueueSize();
 
     size_t initLen = inBufLen;
-    if (initLen > bufStart + bufLen - inBufStart)
+    if (initLen > ((size_t) ((bufStart - inBufStart) + bufLen)))
     {
-        initLen = bufStart + bufLen - inBufStart;
+        initLen = (size_t) ((bufStart - inBufStart) + bufLen);
     }
 
     err = writer.StartContainer(AnonymousTag, kTLVType_Structure, container);
diff --git a/src/lib/profiles/data-management/Current/NotificationEngine.cpp b/src/lib/profiles/data-management/Current/NotificationEngine.cpp
index f26df90..573da3a 100644
--- a/src/lib/profiles/data-management/Current/NotificationEngine.cpp
+++ b/src/lib/profiles/data-management/Current/NotificationEngine.cpp
@@ -1033,6 +1033,7 @@
     mCurSubscriptionHandlerIdx = 0;
     mCurTraitInstanceIdx       = 0;
     mNumNotifiesInFlight       = 0;
+    mNotifyTxEnabled           = true;
 
     return WEAVE_NO_ERROR;
 }
@@ -1761,6 +1762,10 @@
     bool isClean  = true;
     bool isLocked = false;
 
+
+    VerifyOrExit(mNotifyTxEnabled, WeaveLogProgress(DataManagement, "Notify Transmission disabled. Enable to send Notifies");
+                 err = WEAVE_NO_ERROR);
+
     // Lock before attempting to modify any of the shared data structures.
     err = subEngine->Lock();
     SuccessOrExit(err);
@@ -1850,3 +1855,23 @@
 
     return;
 }
+
+WEAVE_ERROR NotificationEngine::EnableNotifications(void)
+{
+    WEAVE_ERROR err  = WEAVE_NO_ERROR;
+
+    WeaveLogDetail(DataManagement, "<NE> Enabling notifications!");
+    mNotifyTxEnabled = true;
+
+    return err;
+}
+
+WEAVE_ERROR NotificationEngine::DisableNotifications(void)
+{
+    WEAVE_ERROR err  = WEAVE_NO_ERROR;
+
+    WeaveLogDetail(DataManagement, "<NE> Disabling notifications!");
+    mNotifyTxEnabled = false;
+
+    return err;
+}
diff --git a/src/lib/profiles/data-management/Current/NotificationEngine.h b/src/lib/profiles/data-management/Current/NotificationEngine.h
index 22cfad7..b0c666c 100644
--- a/src/lib/profiles/data-management/Current/NotificationEngine.h
+++ b/src/lib/profiles/data-management/Current/NotificationEngine.h
@@ -128,6 +128,16 @@
     void ScheduleRun(void);
 
     /**
+     * Enable sending WDM notifications.
+     */
+    WEAVE_ERROR EnableNotifications(void);
+
+    /**
+     * Disable sending WDM notifications.
+     */
+    WEAVE_ERROR DisableNotifications(void);
+
+    /**
      * Marks a handle associated with a data source as being dirty.
      *
      * @retval #WEAVE_NO_ERROR On success.
@@ -416,6 +426,7 @@
     uint32_t mCurSubscriptionHandlerIdx;
     uint32_t mCurTraitInstanceIdx;
     uint32_t mNumNotifiesInFlight;
+    bool     mNotifyTxEnabled;
     nl::Weave::TLV::TLVType mOuterContainerType;
     WEAVE_CONFIG_WDM_PUBLISHER_GRAPH_SOLVER mGraphSolver;
 };
diff --git a/src/lib/profiles/data-management/Current/SubscriptionClient.cpp b/src/lib/profiles/data-management/Current/SubscriptionClient.cpp
index a4319f1..f4dee8f 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionClient.cpp
+++ b/src/lib/profiles/data-management/Current/SubscriptionClient.cpp
@@ -576,6 +576,9 @@
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
 
+    // Make double sure the protocol callback is set on the binding object
+    mBinding->SetProtocolLayerCallback(BindingEventCallback, this);
+
     WeaveLogDetail(DataManagement, "Client[%u] [%5.5s] %s Ref(%d)", SubscriptionEngine::GetInstance()->GetClientId(this),
                    GetStateStr(), __func__, mRefCount);
     _AddRef();
diff --git a/src/lib/profiles/data-management/Current/SubscriptionHandler.cpp b/src/lib/profiles/data-management/Current/SubscriptionHandler.cpp
index 273f372..a4ec1bc 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionHandler.cpp
+++ b/src/lib/profiles/data-management/Current/SubscriptionHandler.cpp
@@ -509,14 +509,27 @@
                     (static_cast<uint32_t>(importance) >= static_cast<uint32_t>(kImportanceType_First)) &&
                     (static_cast<uint32_t>(importance) <= static_cast<uint32_t>(kImportanceType_Last)))
                 {
-                    // We add one to the observed event ID because
-                    // mSelfVendedEvents should point to the next event ID that
-                    // we publish. Otherwise, we would publish an event that
-                    // the subscriber already received.
                     uint32_t i = static_cast<uint32_t>(importance) - static_cast<uint32_t>(kImportanceType_First);
-                    WeaveLogProgress(DataManagement, "Update mSelfVendedEvents[%d] from %d to %d using service data",
-                                     i, mSelfVendedEvents[i], eventId + 1);
-                    mSelfVendedEvents[i] = static_cast<event_id_t>(eventId + 1);
+#if WEAVE_CONFIG_PERSIST_SUBSCRIPTION_STATE
+                    if (DeliveredEventsExist((ImportanceType) importance))
+                    {
+                        WeaveLogProgress(DataManagement, "Update mSelfVendedEvents[%d] from %d to %d using device data",
+                                         i, mSelfVendedEvents[i], 1 + mDeliveredEvents[i]);
+                        mSelfVendedEvents[i] = 1 + mDeliveredEvents[i];
+                    }
+                    else
+                    {
+#endif // WEAVE_CONFIG_PERSIST_SUBSCRIPTION_STATE
+                        // We add one to the observed event ID because
+                        // mSelfVendedEvents should point to the next event ID that
+                        // we publish. Otherwise, we would publish an event that
+                        // the subscriber already received.
+                        WeaveLogProgress(DataManagement, "Update mSelfVendedEvents[%d] from %d to %d using service data",
+                                         i, mSelfVendedEvents[i], eventId + 1);
+                        mSelfVendedEvents[i] = static_cast<event_id_t>(eventId + 1);
+#if WEAVE_CONFIG_PERSIST_SUBSCRIPTION_STATE
+                    }
+#endif // WEAVE_CONFIG_PERSIST_SUBSCRIPTION_STATE
                 }
                 else
                 {
@@ -643,8 +656,18 @@
 #if WEAVE_CONFIG_PERSIST_SUBSCRIPTION_STATE
 void SubscriptionHandler::UpdateDeliveredEvents(ImportanceType importance)
 {
-  uint32_t i = static_cast<uint32_t>(importance) - static_cast<uint32_t>(kImportanceType_First);
-  mDeliveredEvents[i] = mSelfVendedEvents[i] - 1;
+    uint32_t i = static_cast<uint32_t>(importance) - static_cast<uint32_t>(kImportanceType_First);
+    mDeliveredEvents[i] = mSelfVendedEvents[i] - 1;
+}
+
+bool SubscriptionHandler::DeliveredEventsExist(ImportanceType importance)
+{
+    uint32_t i = static_cast<uint32_t>(importance) - static_cast<uint32_t>(kImportanceType_First);
+    if (mDeliveredEvents[i] != 0)
+    {
+        return true;
+    }
+    return false;
 }
 #endif // WEAVE_CONFIG_PERSIST_SUBSCRIPTION_STATE
 
@@ -1785,7 +1808,6 @@
 
     // Capture the binding and arrange to receive event callbacks.
     mBinding->AddRef();
-    mBinding->SetProtocolLayerCallback(BindingEventCallback, this);
 
     mBytesOffloaded = 0;
 
@@ -1964,14 +1986,6 @@
             // mNumTraitInstanceList has already be incremented
             mTraitInstanceList = traitInstance;
         }
-
-        // TODO (didis) Check if data source is persisted, set to dirty if trait data changed from persisted data
-        WeaveLogDetail(DataManagement, "Handler[%u] Syncing is requested for trait[%u].path[%u]",
-                       SubscriptionEngine::GetInstance()->GetHandlerId(this), traitDataHandle, kRootPropertyPathHandle);
-        err = SubscriptionEngine::GetInstance()->mPublisherCatalog->Locate(traitDataHandle, &dataSource);
-        SuccessOrExit(err);
-        dataSource->SetRootDirty();
-        traitInstance->SetDirty();
     }
 
     if (err != WEAVE_END_OF_TLV)
diff --git a/src/lib/profiles/data-management/Current/SubscriptionHandler.h b/src/lib/profiles/data-management/Current/SubscriptionHandler.h
index 90fdd72..85ff081 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionHandler.h
+++ b/src/lib/profiles/data-management/Current/SubscriptionHandler.h
@@ -351,6 +351,7 @@
 
 #if WEAVE_CONFIG_PERSIST_SUBSCRIPTION_STATE
     void UpdateDeliveredEvents(ImportanceType importance);
+    bool DeliveredEventsExist(ImportanceType importance);
 #endif // WEAVE_CONFIG_PERSIST_SUBSCRIPTION_STATE
 
     static void BindingEventCallback(void * const apAppState, const Binding::EventType aEvent,
diff --git a/src/lib/profiles/data-management/Current/UpdateClient.h b/src/lib/profiles/data-management/Current/UpdateClient.h
index 387ebe5..d017191 100644
--- a/src/lib/profiles/data-management/Current/UpdateClient.h
+++ b/src/lib/profiles/data-management/Current/UpdateClient.h
@@ -83,7 +83,6 @@
     EventCallback mEventCallback;
     nl::Weave::ExchangeContext * mEC;
     UpdateClientState mState;
-    utc_timestamp_t mExpiryTimeMicroSecond;
 
     static void OnSendError(ExchangeContext * aEC, WEAVE_ERROR aErrorCode, void * aMsgSpecificContext);
     static void OnResponseTimeout(nl::Weave::ExchangeContext * aEC);
diff --git a/src/lib/profiles/data-management/Current/UpdateEncoder.h b/src/lib/profiles/data-management/Current/UpdateEncoder.h
index 6ca95f4..874fa89 100644
--- a/src/lib/profiles/data-management/Current/UpdateEncoder.h
+++ b/src/lib/profiles/data-management/Current/UpdateEncoder.h
@@ -138,7 +138,13 @@
      */
     struct DataElementDataContext
     {
-        DataElementDataContext() { memset(this, 0, sizeof(*this)); }
+        DataElementDataContext() :
+            mTraitPath(0, 0),
+            mUpdateRequiredVersion(0),
+            mForceMerge(false),
+            mDataSink(nullptr),
+            mSchemaEngine(nullptr),
+            mNextDictionaryElementPathHandle(0) { }
 
         TraitPath mTraitPath;                   /**< The TraitPath to encode. */
         DataVersion mUpdateRequiredVersion;     /**< If the update is conditional, the version the update is based off. */
diff --git a/src/lib/profiles/security/WeaveKeyExportClient.cpp b/src/lib/profiles/security/WeaveKeyExportClient.cpp
index 72757df..e45d1bc 100644
--- a/src/lib/profiles/security/WeaveKeyExportClient.cpp
+++ b/src/lib/profiles/security/WeaveKeyExportClient.cpp
@@ -504,10 +504,7 @@
                            kDecodeFlag_GenerateTBSHash, cert);
     SuccessOrExit(err);
 
-// we need debug in order to get key export functionality working in mobile-ios
-#if DEBUG
-
-    // If DEBUG is enabled and mTrustPreProdDevices == true, arrange to accept key export responses
+    // If mTrustPreProdDevices == true, arrange to accept key export responses
     // from pre-production devices built with Nest development certificates.
 
     if (mAllowNestDevDevices)
@@ -529,8 +526,6 @@
         SuccessOrExit(err);
     }
 
-#endif //DEBUG
-
 exit:
     if (err != WEAVE_NO_ERROR && certSetInitialized)
     {
diff --git a/src/lib/profiles/weave-tunneling/WeaveTunnelAgent.cpp b/src/lib/profiles/weave-tunneling/WeaveTunnelAgent.cpp
index f1c5a2e..548ecb1 100644
--- a/src/lib/profiles/weave-tunneling/WeaveTunnelAgent.cpp
+++ b/src/lib/profiles/weave-tunneling/WeaveTunnelAgent.cpp
@@ -40,15 +40,20 @@
 #include <Weave/Support/WeaveFaultInjection.h>
 #include <Weave/Profiles/weave-tunneling/WeaveTunnelCommon.h>
 #include <Weave/Profiles/weave-tunneling/WeaveTunnelControl.h>
+#include <Weave/Support/logging/DecodedIPPacket.h>
+#include <Weave/Core/WeaveEncoding.h>
 
 #if WEAVE_CONFIG_ENABLE_TUNNELING
 
 #if WEAVE_SYSTEM_CONFIG_USE_LWIP
 #include "lwip/ip6.h"
 #include "lwip/ip6_addr.h"
+#include "lwip/sockets.h"
+#include "lwip/udp.h"
 #else
 #include <arpa/inet.h>
 #include <netinet/in.h>
+#include <netinet/udp.h>
 #include <netinet/ip6.h>
 #endif
 
@@ -934,6 +939,150 @@
 #endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
 }
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
+struct PseudoHeader {
+    uint16_t    PayloadLength;
+    uint16_t    Protocol;
+    uint8_t     SrcAddr[16];
+    uint8_t     DstAddr[16];
+};
+
+uint32_t WeaveTunnelAgent::Checksum(uint16_t *buf, uint16_t len)
+{
+    uint32_t sum    = 0;
+    uint16_t result = 0;
+
+    while (len > 1)
+    {
+        sum += *buf++;
+        len -= 2;
+    }
+
+    if (len == 1)
+    {
+        *(uint8_t *)(&result) = *(uint8_t *)buf;
+        sum += result;
+    }
+
+    return sum;
+}
+
+WEAVE_ERROR WeaveTunnelAgent::ComputeUDPChecksumForIPv6Pkt(PacketBuffer *inMsg, const IPAddress &srcAddr, const IPAddress &destAddr)
+{
+    WEAVE_ERROR       err   = WEAVE_NO_ERROR;
+    uint8_t           *p    = NULL;
+    uint16_t          *q    = NULL;
+    PseudoHeader  payloadWithPseudoHdr;
+    uint16_t udpPktLen = 0;
+    uint32_t sum    = 0;
+    uint16_t *currCSumPtr = 0;
+    uint16_t cSumDataLen = 0;
+
+    // The beginning of the IPv6 packet
+    p = inMsg->Start() + TUN_HDR_SIZE_IN_BYTES;
+
+    // The paylload of the IPv6 packet
+    q = (uint16_t *)(p + sizeof(struct ip6_hdr));
+
+#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+    struct udphdr *udpHdr  = (struct udphdr *)(q);
+
+    // Initialize checksum to 0
+    udpHdr->check = 0;
+#else // !WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+    struct udp_hdr *udpHdr =  (struct udp_hdr *)(q);
+
+    // Initialize checksum to 0
+    udpHdr->chksum = 0;
+#endif // !WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+
+    struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p;
+
+    // Get the UDP length or the IPv6 payload length
+    udpPktLen = inMsg->DataLength() - TUN_HDR_SIZE_IN_BYTES - sizeof(struct ip6_hdr);
+
+    //Fill up IPv6 fields belonging to the pseudo header necessary to calculate the checksum.
+    payloadWithPseudoHdr.PayloadLength   = nl::Weave::Encoding::BigEndian::HostSwap16(udpPktLen);
+    payloadWithPseudoHdr.Protocol      = nl::Weave::Encoding::BigEndian::HostSwap16(NL_PROTO_TYPE_UDP);
+    memcpy(payloadWithPseudoHdr.SrcAddr, &srcAddr, sizeof(payloadWithPseudoHdr.SrcAddr));
+    memcpy(payloadWithPseudoHdr.DstAddr, &destAddr, sizeof(payloadWithPseudoHdr.DstAddr));
+
+    // Calculate checksum for the pseudo header
+    sum = Checksum((uint16_t*)&payloadWithPseudoHdr, sizeof(PseudoHeader));
+    // Calculate the UDP Datagram checksum and add to the sum.
+    sum += Checksum(q, udpPktLen);
+
+    // Adjust for carryover
+    sum = (sum >> 16) + (sum & 0xffff);
+    sum += (sum >> 16);
+    sum = ~sum;
+
+#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+    // Set the new computed checksum result
+    udpHdr->check = ((uint16_t)sum == 0x0000) ? 0xFFFF : (uint16_t)sum;
+    WeaveLogDetail(WeaveTunnel, "New checksum = %x", udpHdr->check);
+#else // !WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+    // Set the new computed checksum result
+    udpHdr->chksum = ((uint16_t)sum == 0x0000) ? 0xFFFF : (uint16_t)sum;
+    WeaveLogDetail(WeaveTunnel, "New checksum = %x", udpHdr->chksum);
+#endif // !WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+
+    return err;
+}
+
+WEAVE_ERROR WeaveTunnelAgent::ReplaceDestSubnetInAddress(PacketBuffer *inMsg, const uint16_t subnetId)
+{
+    WEAVE_ERROR      err   = WEAVE_NO_ERROR;
+    uint8_t           *p   = NULL;
+    struct ip6_hdr *ip6hdr = NULL;
+    IPAddress inDest, srcAddr, replacedDestAddr;
+#if WEAVE_SYSTEM_CONFIG_USE_LWIP
+    ip6_addr_t ipv6Addr;
+#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
+
+#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+    struct in6_addr ipv6Addr;
+#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+
+    // Extract the IPv6 header to look at the destination address
+
+    p = inMsg->Start() + TUN_HDR_SIZE_IN_BYTES;
+
+    ip6hdr = (struct ip6_hdr *)p;
+
+    // Fetch destination address from header
+#if WEAVE_SYSTEM_CONFIG_USE_LWIP
+    ip6_addr_copy(ipv6Addr, ip6hdr->dest);
+    inDest = IPAddress::FromIPv6(ipv6Addr);
+
+    ip6_addr_copy(ipv6Addr, ip6hdr->src);
+    srcAddr = IPAddress::FromIPv6(ipv6Addr);
+#else // !WEAVE_SYSTEM_CONFIG_USE_LWIP
+    inDest = IPAddress::FromIPv6(ip6hdr->ip6_dst);
+    srcAddr = IPAddress::FromIPv6(ip6hdr->ip6_src);
+#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
+
+    replacedDestAddr = IPAddress::MakeULA(inDest.GlobalId(), subnetId, inDest.InterfaceId());
+
+    // Set correct destination address
+
+#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+    ip6hdr->ip6_dst = replacedDestAddr.ToIPv6();
+#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+
+#if WEAVE_SYSTEM_CONFIG_USE_LWIP
+    ipv6Addr = replacedDestAddr.ToIPv6();
+    ip6_addr_copy(ip6hdr->dest, ipv6Addr);
+#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
+
+    // Recompute UDP checksum to account for the destination address change
+    err = ComputeUDPChecksumForIPv6Pkt(inMsg, srcAddr, replacedDestAddr);
+
+    return err;
+}
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
 /**
  * Handler to receive IPv6 packets from the Tunnel EndPoint interface and forward, either to the Service
  * via the Service TCP connection after encapsulating IPv6 packet inside the tunnel header or to the Mobile
@@ -958,6 +1107,7 @@
     SuccessOrExit(err);
 
     nodeId = destIP6Addr.InterfaceId();
+
     if (destIP6Addr.Subnet() == kWeaveSubnetId_Service)
     {
         // Destined for Service
@@ -993,6 +1143,18 @@
             SuccessOrExit(err);
         }
     }
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    else if (destIP6Addr.Subnet() == kWeaveSubnetId_TunneledCapture)
+    {
+        WeaveLogDetail(WeaveTunnel, "Tunneled message received with Capture subnet. Replacing with Service Subnet\n");
+        err = tAgent->ReplaceDestSubnetInAddress(msg, kWeaveSubnetId_Service);
+        SuccessOrExit(err);
+
+        err = tAgent->HandleSendingToService(msg, true);
+        msg = NULL;
+        SuccessOrExit(err);
+    }
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
 
 exit:
     if (msg != NULL)
@@ -1164,8 +1326,6 @@
 void WeaveTunnelAgent::PopulateTunnelMsgHeader(WeaveMessageInfo *msgInfo,
                                                const WeaveTunnelConnectionMgr *connMgr)
 {
-    msgInfo->Clear();
-
     // Set to no-encryption when not using a tunnel to the Service
 
     if (!connMgr)
@@ -1262,10 +1422,13 @@
 /**
  * Prepare message and send to Service via Remote tunnel.
  */
-WEAVE_ERROR WeaveTunnelAgent::HandleSendingToService(PacketBuffer *msg)
+WEAVE_ERROR WeaveTunnelAgent::HandleSendingToService(PacketBuffer *msg, const bool shouldCapture)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     bool dropPacket = false;
+    WeaveMessageInfo msgInfo;
+
+    msgInfo.Clear();
 
     if (mPrimaryTunConnMgr.mConnectionState != WeaveTunnelConnectionMgr::kState_TunnelOpen
 #if WEAVE_CONFIG_TUNNEL_FAILOVER_SUPPORTED
@@ -1286,12 +1449,18 @@
         ExitNow();
     }
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    if (shouldCapture)
+    {
+        WeaveLogDetail(WeaveTunnel, "Tagging Tunneled message for capture\n");
+        msgInfo.Flags |= kWeaveMessageFlag_CaptureTxMessage;
+    }
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
     // Send on primary tunnel if open; else send over backup tunnel
 
     if (mPrimaryTunConnMgr.mConnectionState == WeaveTunnelConnectionMgr::kState_TunnelOpen)
     {
-        WeaveMessageInfo msgInfo;
-
         PopulateTunnelMsgHeader(&msgInfo, &mPrimaryTunConnMgr);
 
         err = SendMessageUponPktTransitAnalysis(&mPrimaryTunConnMgr, kDir_Outbound, kType_TunnelPrimary,
@@ -1300,8 +1469,6 @@
 #if WEAVE_CONFIG_TUNNEL_FAILOVER_SUPPORTED
     else if (mBackupTunConnMgr.mConnectionState == WeaveTunnelConnectionMgr::kState_TunnelOpen)
     {
-        WeaveMessageInfo msgInfo;
-
         PopulateTunnelMsgHeader(&msgInfo, &mBackupTunConnMgr);
 
         err = SendMessageUponPktTransitAnalysis(&mBackupTunConnMgr, kDir_Outbound, kType_TunnelBackup,
diff --git a/src/lib/profiles/weave-tunneling/WeaveTunnelAgent.h b/src/lib/profiles/weave-tunneling/WeaveTunnelAgent.h
index bd3455c..01d1fa9 100644
--- a/src/lib/profiles/weave-tunneling/WeaveTunnelAgent.h
+++ b/src/lib/profiles/weave-tunneling/WeaveTunnelAgent.h
@@ -654,7 +654,7 @@
     // Message encapsulating/decapsulating functions for sending between Tunnel and other interfaces
 
     WEAVE_ERROR AddTunnelHdrToMsg(PacketBuffer *msg);
-    WEAVE_ERROR HandleSendingToService(PacketBuffer *msg);
+    WEAVE_ERROR HandleSendingToService(PacketBuffer *msg, const bool shouldCapture = false);
     WEAVE_ERROR HandleTunneledReceive(PacketBuffer *msg, TunnelType tunType);
 
     /// Decide based on lookup of nexthop table and send locally
@@ -718,6 +718,13 @@
     void WeaveTunnelNotifyTCPSendIdleStateChange(const TunnelType tunType, const bool isIdle);
 #endif // WEAVE_CONFIG_TUNNEL_ENABLE_TCP_IDLE_CALLBACK
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    WEAVE_ERROR ReplaceDestSubnetInAddress(PacketBuffer *inMsg, const uint16_t subnetId);
+
+    WEAVE_ERROR ComputeUDPChecksumForIPv6Pkt(PacketBuffer *inMsg, const IPAddress &srcAddr, const IPAddress &destAddr);
+    uint32_t Checksum(uint16_t *buf, uint16_t len);
+
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
 };
 
 
diff --git a/src/lib/support/StatusReportStr.cpp b/src/lib/support/StatusReportStr.cpp
index c52251a..fcb0f18 100644
--- a/src/lib/support/StatusReportStr.cpp
+++ b/src/lib/support/StatusReportStr.cpp
@@ -101,238 +101,254 @@
 
 NL_DLL_EXPORT const char *StatusReportStr(uint32_t profileId, uint16_t statusCode)
 {
-    const char *fmt = NULL;
+    const char *fmt = "[ %s(%08" PRIX32 "):%" PRIu16 " ] %s";
+    const char *profileName = NULL;
+    const char *errorMsg = "";
 
     switch (profileId)
     {
     case kWeaveProfile_BDX:
+        profileName = "BDX";
         switch (statusCode)
         {
 #if WEAVE_CONFIG_BDX_NAMESPACE == kWeaveManagedNamespace_Development
-        case BulkDataTransfer::kStatus_Overflow                                         : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Overflow"; break;
-        case BulkDataTransfer::kStatus_LengthTooShort                                   : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Length too short"; break;
-        case BulkDataTransfer::kStatus_XferFailedUnknownErr                             : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Transfer failed for unknown reason"; break;
-        case BulkDataTransfer::kStatus_XferMethodNotSupported                           : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Transfer method not supported"; break;
-        case BulkDataTransfer::kStatus_UnknownFile                                      : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Unknown file"; break;
-        case BulkDataTransfer::kStatus_StartOffsetNotSupported                          : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Start offset not support"; break;
-        case BulkDataTransfer::kStatus_Unknown                                          : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Unknown error"; break;
+        case BulkDataTransfer::kStatus_Overflow                            : errorMsg = "Overflow"; break;
+        case BulkDataTransfer::kStatus_LengthTooShort                      : errorMsg = "Length too short"; break;
+        case BulkDataTransfer::kStatus_XferFailedUnknownErr                : errorMsg = "Transfer failed for unknown reason"; break;
+        case BulkDataTransfer::kStatus_XferMethodNotSupported              : errorMsg = "Transfer method not supported"; break;
+        case BulkDataTransfer::kStatus_UnknownFile                         : errorMsg = "Unknown file"; break;
+        case BulkDataTransfer::kStatus_StartOffsetNotSupported             : errorMsg = "Start offset not support"; break;
+        case BulkDataTransfer::kStatus_Unknown                             : errorMsg = "Unknown error"; break;
 #else
-        case BulkDataTransfer::kStatus_Overflow                                         : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Overflow"; break;
-        case BulkDataTransfer::kStatus_LengthTooLarge                                   : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Length too long"; break;
-        case BulkDataTransfer::kStatus_LengthTooShort                                   : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Length too short"; break;
-        case BulkDataTransfer::kStatus_LengthMismatch                                   : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Length mismatch"; break;
-        case BulkDataTransfer::kStatus_LengthRequired                                   : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Length required"; break;
-        case BulkDataTransfer::kStatus_BadMessageContents                               : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Bad message contents"; break;
-        case BulkDataTransfer::kStatus_BadBlockCounter                                  : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Bad block counter"; break;
-        case BulkDataTransfer::kStatus_XferFailedUnknownErr                             : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Transfer failed for unknown reason"; break;
-        case BulkDataTransfer::kStatus_ServerBadState                                   : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Server is in incorrect state"; break;
-        case BulkDataTransfer::kStatus_FailureToSend                                    : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Failure to send"; break;
-        case BulkDataTransfer::kStatus_XferMethodNotSupported                           : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Transfer method not supported"; break;
-        case BulkDataTransfer::kStatus_UnknownFile                                      : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Unknown file"; break;
-        case BulkDataTransfer::kStatus_StartOffsetNotSupported                          : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Start offset not support"; break;
-        case BulkDataTransfer::kStatus_VersionNotSupported                              : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Protocol version not supported"; break;
-        case BulkDataTransfer::kStatus_Unknown                                          : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ] Unknown error"; break;
+        case BulkDataTransfer::kStatus_Overflow                            : errorMsg = "Overflow"; break;
+        case BulkDataTransfer::kStatus_LengthTooLarge                      : errorMsg = "Length too long"; break;
+        case BulkDataTransfer::kStatus_LengthTooShort                      : errorMsg = "Length too short"; break;
+        case BulkDataTransfer::kStatus_LengthMismatch                      : errorMsg = "Length mismatch"; break;
+        case BulkDataTransfer::kStatus_LengthRequired                      : errorMsg = "Length required"; break;
+        case BulkDataTransfer::kStatus_BadMessageContents                  : errorMsg = "Bad message contents"; break;
+        case BulkDataTransfer::kStatus_BadBlockCounter                     : errorMsg = "Bad block counter"; break;
+        case BulkDataTransfer::kStatus_XferFailedUnknownErr                : errorMsg = "Transfer failed for unknown reason"; break;
+        case BulkDataTransfer::kStatus_ServerBadState                      : errorMsg = "Server is in incorrect state"; break;
+        case BulkDataTransfer::kStatus_FailureToSend                       : errorMsg = "Failure to send"; break;
+        case BulkDataTransfer::kStatus_XferMethodNotSupported              : errorMsg = "Transfer method not supported"; break;
+        case BulkDataTransfer::kStatus_UnknownFile                         : errorMsg = "Unknown file"; break;
+        case BulkDataTransfer::kStatus_StartOffsetNotSupported             : errorMsg = "Start offset not support"; break;
+        case BulkDataTransfer::kStatus_VersionNotSupported                 : errorMsg = "Protocol version not supported"; break;
+        case BulkDataTransfer::kStatus_Unknown                             : errorMsg = "Unknown error"; break;
 #endif // WEAVE_CONFIG_BDX_NAMESPACE == kWeaveManagedNamespace_Development
-        default                                                                         : fmt = "[ BDX(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_Common:
+        profileName = "Common";
         switch (statusCode)
         {
-        case nl::Weave::Profiles::Common::kStatus_Success                               : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Success"; break;
-        case nl::Weave::Profiles::Common::kStatus_Canceled                              : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Canceled"; break;
-        case nl::Weave::Profiles::Common::kStatus_BadRequest                            : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Bad/malformed request"; break;
-        case nl::Weave::Profiles::Common::kStatus_UnsupportedMessage                    : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Unrecognized/unsupported message"; break;
-        case nl::Weave::Profiles::Common::kStatus_UnexpectedMessage                     : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Unexpected message"; break;
-        case nl::Weave::Profiles::Common::kStatus_AuthenticationRequired                : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Authentication required"; break;
-        case nl::Weave::Profiles::Common::kStatus_AccessDenied                          : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Access denied"; break;
-        case nl::Weave::Profiles::Common::kStatus_OutOfMemory                           : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Out of memory"; break;
-        case nl::Weave::Profiles::Common::kStatus_NotAvailable                          : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Not available"; break;
-        case nl::Weave::Profiles::Common::kStatus_LocalSetupRequired                    : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Local setup required"; break;
-        case nl::Weave::Profiles::Common::kStatus_Relocated                             : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Relocated"; break;
-        case nl::Weave::Profiles::Common::kStatus_Busy                                  : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Sender busy"; break;
-        case nl::Weave::Profiles::Common::kStatus_Timeout                               : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Timeout"; break;
-        case nl::Weave::Profiles::Common::kStatus_InternalError                         : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Internal error"; break;
-        case nl::Weave::Profiles::Common::kStatus_Continue                              : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ] Continue"; break;
-        default                                                                         : fmt = "[ Common(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case nl::Weave::Profiles::Common::kStatus_Success                  : errorMsg = "Success"; break;
+        case nl::Weave::Profiles::Common::kStatus_Canceled                 : errorMsg = "Canceled"; break;
+        case nl::Weave::Profiles::Common::kStatus_BadRequest               : errorMsg = "Bad/malformed request"; break;
+        case nl::Weave::Profiles::Common::kStatus_UnsupportedMessage       : errorMsg = "Unrecognized/unsupported message"; break;
+        case nl::Weave::Profiles::Common::kStatus_UnexpectedMessage        : errorMsg = "Unexpected message"; break;
+        case nl::Weave::Profiles::Common::kStatus_AuthenticationRequired   : errorMsg = "Authentication required"; break;
+        case nl::Weave::Profiles::Common::kStatus_AccessDenied             : errorMsg = "Access denied"; break;
+        case nl::Weave::Profiles::Common::kStatus_OutOfMemory              : errorMsg = "Out of memory"; break;
+        case nl::Weave::Profiles::Common::kStatus_NotAvailable             : errorMsg = "Not available"; break;
+        case nl::Weave::Profiles::Common::kStatus_LocalSetupRequired       : errorMsg = "Local setup required"; break;
+        case nl::Weave::Profiles::Common::kStatus_Relocated                : errorMsg = "Relocated"; break;
+        case nl::Weave::Profiles::Common::kStatus_Busy                     : errorMsg = "Sender busy"; break;
+        case nl::Weave::Profiles::Common::kStatus_Timeout                  : errorMsg = "Timeout"; break;
+        case nl::Weave::Profiles::Common::kStatus_InternalError            : errorMsg = "Internal error"; break;
+        case nl::Weave::Profiles::Common::kStatus_Continue                 : errorMsg = "Continue"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_WDM:
+        profileName = "WDM";
         switch (statusCode)
             {
-        case DataManagement_Legacy::kStatus_CancelSuccess                               : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Subscription canceled"; break;
-        case DataManagement_Legacy::kStatus_InvalidPath                                 : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Invalid path"; break;
-        case DataManagement_Legacy::kStatus_UnknownTopic                                : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Unknown topic"; break;
-        case DataManagement_Legacy::kStatus_IllegalReadRequest                          : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Illegal read request"; break;
-        case DataManagement_Legacy::kStatus_IllegalWriteRequest                         : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Illegal write request"; break;
-        case DataManagement_Legacy::kStatus_InvalidVersion                              : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Invalid version"; break;
-        case DataManagement_Legacy::kStatus_UnsupportedSubscriptionMode                 : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Unsupported subscription mode"; break;
+        case DataManagement_Legacy::kStatus_CancelSuccess                  : errorMsg = "Subscription canceled"; break;
+        case DataManagement_Legacy::kStatus_InvalidPath                    : errorMsg = "Invalid path"; break;
+        case DataManagement_Legacy::kStatus_UnknownTopic                   : errorMsg = "Unknown topic"; break;
+        case DataManagement_Legacy::kStatus_IllegalReadRequest             : errorMsg = "Illegal read request"; break;
+        case DataManagement_Legacy::kStatus_IllegalWriteRequest            : errorMsg = "Illegal write request"; break;
+        case DataManagement_Legacy::kStatus_InvalidVersion                 : errorMsg = "Invalid version"; break;
+        case DataManagement_Legacy::kStatus_UnsupportedSubscriptionMode    : errorMsg = "Unsupported subscription mode"; break;
 
-        case DataManagement_Current::kStatus_InvalidValueInNotification                 : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Invalid value in notification"; break;
-        case DataManagement_Current::kStatus_InvalidPath                                : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Invalid path"; break;
-        case DataManagement_Current::kStatus_ExpiryTimeNotSupported                     : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Expiry time not supported"; break;
-        case DataManagement_Current::kStatus_NotTimeSyncedYet                           : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Not time-synced yet"; break;
-        case DataManagement_Current::kStatus_RequestExpiredInTime                       : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Request expired in time"; break;
-        case DataManagement_Current::kStatus_VersionMismatch                            : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Version mismatch"; break;
-        case DataManagement_Current::kStatus_GeneralProtocolError                       : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] General protocol error"; break;
-        case DataManagement_Current::kStatus_SecurityError                              : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Security error"; break;
-        case DataManagement_Current::kStatus_InvalidSubscriptionID                      : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Invalid subscription ID"; break;
-        case DataManagement_Current::kStatus_GeneralSchemaViolation                     : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] General schema violation"; break;
-        case DataManagement_Current::kStatus_UnpairedDeviceRejected                     : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Unpaired device rejected"; break;
-        case DataManagement_Current::kStatus_IncompatibleDataSchemaVersion              : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Incompatible data schema violation"; break;
-        case DataManagement_Current::kStatus_MultipleFailures                           : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Multiple failures"; break;
-        case DataManagement_Current::kStatus_UpdateOutOfSequence                        : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ] Update out of sequence"; break;
-        default                                                                         : fmt = "[ WDM(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case DataManagement_Current::kStatus_InvalidValueInNotification    : errorMsg = "Invalid value in notification"; break;
+        case DataManagement_Current::kStatus_InvalidPath                   : errorMsg = "Invalid path"; break;
+        case DataManagement_Current::kStatus_ExpiryTimeNotSupported        : errorMsg = "Expiry time not supported"; break;
+        case DataManagement_Current::kStatus_NotTimeSyncedYet              : errorMsg = "Not time-synced yet"; break;
+        case DataManagement_Current::kStatus_RequestExpiredInTime          : errorMsg = "Request expired in time"; break;
+        case DataManagement_Current::kStatus_VersionMismatch               : errorMsg = "Version mismatch"; break;
+        case DataManagement_Current::kStatus_GeneralProtocolError          : errorMsg = "General protocol error"; break;
+        case DataManagement_Current::kStatus_SecurityError                 : errorMsg = "Security error"; break;
+        case DataManagement_Current::kStatus_InvalidSubscriptionID         : errorMsg = "Invalid subscription ID"; break;
+        case DataManagement_Current::kStatus_GeneralSchemaViolation        : errorMsg = "General schema violation"; break;
+        case DataManagement_Current::kStatus_UnpairedDeviceRejected        : errorMsg = "Unpaired device rejected"; break;
+        case DataManagement_Current::kStatus_IncompatibleDataSchemaVersion : errorMsg = "Incompatible data schema violation"; break;
+        case DataManagement_Current::kStatus_MultipleFailures              : errorMsg = "Multiple failures"; break;
+        case DataManagement_Current::kStatus_UpdateOutOfSequence           : errorMsg = "Update out of sequence"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_DeviceControl:
+        profileName = "DeviceControl";
         switch (statusCode)
         {
-        case DeviceControl::kStatusCode_FailSafeAlreadyActive                           : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] Fail-safe already active"; break;
-        case DeviceControl::kStatusCode_NoFailSafeActive                                : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] No fail-safe active"; break;
-        case DeviceControl::kStatusCode_NoMatchingFailSafeActive                        : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] No matching fail-safe active"; break;
-        case DeviceControl::kStatusCode_UnsupportedFailSafeMode                         : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] Unsupported fail-safe mode"; break;
-        case DeviceControl::kStatusCode_RemotePassiveRendezvousTimedOut                 : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] Remote Passive Rendezvous timed out"; break;
-        case DeviceControl::kStatusCode_UnsecuredListenPreempted                        : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] Unsecured Listen pre-empted"; break;
-        case DeviceControl::kStatusCode_ResetSuccessCloseCon                            : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] ResetConfig will succeed after connection close"; break;
-        case DeviceControl::kStatusCode_ResetNotAllowed                                 : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] Reset not allowed"; break;
-        case DeviceControl::kStatusCode_NoSystemTestDelegate                            : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ] System test cannot run without a delegate"; break;
-        default                                                                         : fmt = "[ DeviceControl(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case DeviceControl::kStatusCode_FailSafeAlreadyActive              : errorMsg = "Fail-safe already active"; break;
+        case DeviceControl::kStatusCode_NoFailSafeActive                   : errorMsg = "No fail-safe active"; break;
+        case DeviceControl::kStatusCode_NoMatchingFailSafeActive           : errorMsg = "No matching fail-safe active"; break;
+        case DeviceControl::kStatusCode_UnsupportedFailSafeMode            : errorMsg = "Unsupported fail-safe mode"; break;
+        case DeviceControl::kStatusCode_RemotePassiveRendezvousTimedOut    : errorMsg = "Remote Passive Rendezvous timed out"; break;
+        case DeviceControl::kStatusCode_UnsecuredListenPreempted           : errorMsg = "Unsecured Listen pre-empted"; break;
+        case DeviceControl::kStatusCode_ResetSuccessCloseCon               : errorMsg = "ResetConfig will succeed after connection close"; break;
+        case DeviceControl::kStatusCode_ResetNotAllowed                    : errorMsg = "Reset not allowed"; break;
+        case DeviceControl::kStatusCode_NoSystemTestDelegate               : errorMsg = "System test cannot run without a delegate"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_DeviceDescription:
+        profileName = "DeviceDescription";
         switch (statusCode)
         {
-        default                                                                         : fmt = "[ DeviceDescription(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_Echo:
+        profileName = "Echo";
         switch (statusCode)
         {
-        default                                                                         : fmt = "[ Echo(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_FabricProvisioning:
+        profileName = "FabricProvisioning";
         switch (statusCode)
         {
-        case FabricProvisioning::kStatusCode_AlreadyMemberOfFabric                      : fmt = "[ FabricProvisioning(%08" PRIX32 "):%" PRIu16 " ] Already member of fabric"; break;
-        case FabricProvisioning::kStatusCode_NotMemberOfFabric                          : fmt = "[ FabricProvisioning(%08" PRIX32 "):%" PRIu16 " ] Not member of fabric"; break;
-        case FabricProvisioning::kStatusCode_InvalidFabricConfig                        : fmt = "[ FabricProvisioning(%08" PRIX32 "):%" PRIu16 " ] Invalid fabric config"; break;
-        default                                                                         : fmt = "[ FabricProvisioning(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case FabricProvisioning::kStatusCode_AlreadyMemberOfFabric         : errorMsg = "Already member of fabric"; break;
+        case FabricProvisioning::kStatusCode_NotMemberOfFabric             : errorMsg = "Not member of fabric"; break;
+        case FabricProvisioning::kStatusCode_InvalidFabricConfig           : errorMsg = "Invalid fabric config"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_NetworkProvisioning:
+        profileName = "NetworkProvisioning";
         switch (statusCode)
         {
-        case NetworkProvisioning::kStatusCode_UnknownNetwork                            : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Unknown network"; break;
-        case NetworkProvisioning::kStatusCode_TooManyNetworks                           : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Too many networks"; break;
-        case NetworkProvisioning::kStatusCode_InvalidNetworkConfiguration               : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Invalid network configuration"; break;
-        case NetworkProvisioning::kStatusCode_UnsupportedNetworkType                    : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Unsupported network configuration"; break;
-        case NetworkProvisioning::kStatusCode_UnsupportedWiFiMode                       : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Unsupported WiFi mode"; break;
-        case NetworkProvisioning::kStatusCode_UnsupportedWiFiRole                       : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Unsupported WiFi role"; break;
-        case NetworkProvisioning::kStatusCode_UnsupportedWiFiSecurityType               : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Unsupported WiFi security type"; break;
-        case NetworkProvisioning::kStatusCode_InvalidState                              : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Invalid state"; break;
-        case NetworkProvisioning::kStatusCode_TestNetworkFailed                         : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Test network failed"; break;
-        case NetworkProvisioning::kStatusCode_NetworkConnectFailed                      : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Network connect failed"; break;
-        case NetworkProvisioning::kStatusCode_NoRouterAvailable                         : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] No router available"; break;
-        case NetworkProvisioning::kStatusCode_UnsupportedRegulatoryDomain               : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Unsupported wireless regulatory domain"; break;
-        case NetworkProvisioning::kStatusCode_UnsupportedOperatingLocation              : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ] Unsupported wireless operating location"; break;
-        default                                                                         : fmt = "[ NetworkProvisioning(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case NetworkProvisioning::kStatusCode_UnknownNetwork               : errorMsg = "Unknown network"; break;
+        case NetworkProvisioning::kStatusCode_TooManyNetworks              : errorMsg = "Too many networks"; break;
+        case NetworkProvisioning::kStatusCode_InvalidNetworkConfiguration  : errorMsg = "Invalid network configuration"; break;
+        case NetworkProvisioning::kStatusCode_UnsupportedNetworkType       : errorMsg = "Unsupported network configuration"; break;
+        case NetworkProvisioning::kStatusCode_UnsupportedWiFiMode          : errorMsg = "Unsupported WiFi mode"; break;
+        case NetworkProvisioning::kStatusCode_UnsupportedWiFiRole          : errorMsg = "Unsupported WiFi role"; break;
+        case NetworkProvisioning::kStatusCode_UnsupportedWiFiSecurityType  : errorMsg = "Unsupported WiFi security type"; break;
+        case NetworkProvisioning::kStatusCode_InvalidState                 : errorMsg = "Invalid state"; break;
+        case NetworkProvisioning::kStatusCode_TestNetworkFailed            : errorMsg = "Test network failed"; break;
+        case NetworkProvisioning::kStatusCode_NetworkConnectFailed         : errorMsg = "Network connect failed"; break;
+        case NetworkProvisioning::kStatusCode_NoRouterAvailable            : errorMsg = "No router available"; break;
+        case NetworkProvisioning::kStatusCode_UnsupportedRegulatoryDomain  : errorMsg = "Unsupported wireless regulatory domain"; break;
+        case NetworkProvisioning::kStatusCode_UnsupportedOperatingLocation : errorMsg = "Unsupported wireless operating location"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_Security:
+        profileName = "Security";
         switch (statusCode)
         {
-        case Security::kStatusCode_SessionAborted                                       : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Session aborted"; break;
-        case Security::kStatusCode_PASESupportsOnlyConfig1                              : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] PASE Engine only supports Config1"; break;
-        case Security::kStatusCode_UnsupportedEncryptionType                            : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Unsupported encryption type"; break;
-        case Security::kStatusCode_InvalidKeyId                                         : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Invalid key id"; break;
-        case Security::kStatusCode_DuplicateKeyId                                       : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Duplicate key id"; break;
-        case Security::kStatusCode_KeyConfirmationFailed                                : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Key confirmation failed"; break;
-        case Security::kStatusCode_InternalError                                        : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Internal error"; break;
-        case Security::kStatusCode_AuthenticationFailed                                 : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Authentication failed"; break;
-        case Security::kStatusCode_UnsupportedCASEConfiguration                         : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Unsupported CASE configuration"; break;
-        case Security::kStatusCode_UnsupportedCertificate                               : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Unsupported certificate"; break;
-        case Security::kStatusCode_NoCommonPASEConfigurations                           : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] No supported PASE configurations in common"; break;
-        case Security::kStatusCode_KeyNotFound                                          : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Key not found"; break;
-        case Security::kStatusCode_WrongEncryptionType                                  : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Wrong encryption type"; break;
-        case Security::kStatusCode_UnknownKeyType                                       : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Unknown key type"; break;
-        case Security::kStatusCode_InvalidUseOfSessionKey                               : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Invalid use of session key"; break;
-        case Security::kStatusCode_InternalKeyError                                     : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Internal key error"; break;
-        case Security::kStatusCode_NoCommonKeyExportConfiguration                       : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] No common key export configuration"; break;
-        case Security::kStatusCode_UnauthorizedKeyExportRequest                         : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Unauthorized key export request"; break;
-        case Security::kStatusCode_NoNewOperationalCertRequired                         : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] No new operational certificate required"; break;
-        case Security::kStatusCode_OperationalNodeIdInUse                               : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Operational node Id collision"; break;
-        case Security::kStatusCode_InvalidOperationalNodeId                             : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Invalid operational node Id"; break;
-        case Security::kStatusCode_InvalidOperationalCertificate                        : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Invalid operational certificate"; break;
-        default                                                                         : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case Security::kStatusCode_SessionAborted                          : errorMsg = "Session aborted"; break;
+        case Security::kStatusCode_PASESupportsOnlyConfig1                 : errorMsg = "PASE Engine only supports Config1"; break;
+        case Security::kStatusCode_UnsupportedEncryptionType               : errorMsg = "Unsupported encryption type"; break;
+        case Security::kStatusCode_InvalidKeyId                            : errorMsg = "Invalid key id"; break;
+        case Security::kStatusCode_DuplicateKeyId                          : errorMsg = "Duplicate key id"; break;
+        case Security::kStatusCode_KeyConfirmationFailed                   : errorMsg = "Key confirmation failed"; break;
+        case Security::kStatusCode_InternalError                           : errorMsg = "Internal error"; break;
+        case Security::kStatusCode_AuthenticationFailed                    : errorMsg = "Authentication failed"; break;
+        case Security::kStatusCode_UnsupportedCASEConfiguration            : errorMsg = "Unsupported CASE configuration"; break;
+        case Security::kStatusCode_UnsupportedCertificate                  : errorMsg = "Unsupported certificate"; break;
+        case Security::kStatusCode_NoCommonPASEConfigurations              : errorMsg = "No supported PASE configurations in common"; break;
+        case Security::kStatusCode_KeyNotFound                             : errorMsg = "Key not found"; break;
+        case Security::kStatusCode_WrongEncryptionType                     : errorMsg = "Wrong encryption type"; break;
+        case Security::kStatusCode_UnknownKeyType                          : errorMsg = "Unknown key type"; break;
+        case Security::kStatusCode_InvalidUseOfSessionKey                  : errorMsg = "Invalid use of session key"; break;
+        case Security::kStatusCode_InternalKeyError                        : errorMsg = "Internal key error"; break;
+        case Security::kStatusCode_NoCommonKeyExportConfiguration          : errorMsg = "No common key export configuration"; break;
+        case Security::kStatusCode_UnauthorizedKeyExportRequest            : errorMsg = "Unauthorized key export request"; break;
+        case Security::kStatusCode_NoNewOperationalCertRequired            : errorMsg = "No new operational certificate required"; break;
+        case Security::kStatusCode_OperationalNodeIdInUse                  : errorMsg = "Operational node Id collision"; break;
+        case Security::kStatusCode_InvalidOperationalNodeId                : errorMsg = "Invalid operational node Id"; break;
+        case Security::kStatusCode_InvalidOperationalCertificate           : errorMsg = "Invalid operational certificate"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 #if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
     case kWeaveProfile_ServiceDirectory:
+        profileName = "ServiceDirectory";
         switch (statusCode)
         {
-        case ServiceDirectory::kStatus_DirectoryUnavailable                             : fmt = "[ ServiceDirectory(%08" PRIX32 "):%" PRIu16 " ] Service directory unavailable"; break;
-        default                                                                         : fmt = "[ ServiceDirectory(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case ServiceDirectory::kStatus_DirectoryUnavailable                : errorMsg = "Service directory unavailable"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 #endif
     case kWeaveProfile_ServiceProvisioning:
+        profileName = "ServiceProvisioning";
         switch (statusCode)
         {
-        case ServiceProvisioning::kStatusCode_TooManyServices                           : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Too many services"; break;
-        case ServiceProvisioning::kStatusCode_ServiceAlreadyRegistered                  : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Service already registered"; break;
-        case ServiceProvisioning::kStatusCode_InvalidServiceConfig                      : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Invalid service configuration"; break;
-        case ServiceProvisioning::kStatusCode_NoSuchService                             : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] No such service"; break;
-        case ServiceProvisioning::kStatusCode_PairingServerError                        : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Error talking to pairing server"; break;
-        case ServiceProvisioning::kStatusCode_InvalidPairingToken                       : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Invalid pairing token"; break;
-        case ServiceProvisioning::kStatusCode_PairingTokenOld                           : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Pairing token no longer valid"; break;
-        case ServiceProvisioning::kStatusCode_ServiceCommunicationError                 : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Service communication error"; break;
-        case ServiceProvisioning::kStatusCode_ServiceConfigTooLarge                     : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Service configuration too large"; break;
-        case ServiceProvisioning::kStatusCode_WrongFabric                               : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Wrong fabric"; break;
-        case ServiceProvisioning::kStatusCode_TooManyFabrics                            : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ] Too many fabrics"; break;
-        default                                                                         : fmt = "[ ServiceProvisioning(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case ServiceProvisioning::kStatusCode_TooManyServices              : errorMsg = "Too many services"; break;
+        case ServiceProvisioning::kStatusCode_ServiceAlreadyRegistered     : errorMsg = "Service already registered"; break;
+        case ServiceProvisioning::kStatusCode_InvalidServiceConfig         : errorMsg = "Invalid service configuration"; break;
+        case ServiceProvisioning::kStatusCode_NoSuchService                : errorMsg = "No such service"; break;
+        case ServiceProvisioning::kStatusCode_PairingServerError           : errorMsg = "Error talking to pairing server"; break;
+        case ServiceProvisioning::kStatusCode_InvalidPairingToken          : errorMsg = "Invalid pairing token"; break;
+        case ServiceProvisioning::kStatusCode_PairingTokenOld              : errorMsg = "Pairing token no longer valid"; break;
+        case ServiceProvisioning::kStatusCode_ServiceCommunicationError    : errorMsg = "Service communication error"; break;
+        case ServiceProvisioning::kStatusCode_ServiceConfigTooLarge        : errorMsg = "Service configuration too large"; break;
+        case ServiceProvisioning::kStatusCode_WrongFabric                  : errorMsg = "Wrong fabric"; break;
+        case ServiceProvisioning::kStatusCode_TooManyFabrics               : errorMsg = "Too many fabrics"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
     case kWeaveProfile_SWU:
+        profileName = "SWU";
         switch (statusCode)
         {
-        case SoftwareUpdate::kStatus_NoUpdateAvailable                                  : fmt = "[ SWU(%08" PRIX32 "):%" PRIu16 " ] No software update available"; break;
-        case SoftwareUpdate::kStatus_UpdateFailed                                       : fmt = "[ SWU(%08" PRIX32 "):%" PRIu16 " ] Software update failed"; break;
-        case SoftwareUpdate::kStatus_InvalidInstructions                                : fmt = "[ SWU(%08" PRIX32 "):%" PRIu16 " ] Invalid software image download instructions"; break;
-        case SoftwareUpdate::kStatus_DownloadFailed                                     : fmt = "[ SWU(%08" PRIX32 "):%" PRIu16 " ] Software image download failed"; break;
-        case SoftwareUpdate::kStatus_IntegrityCheckFailed                               : fmt = "[ SWU(%08" PRIX32 "):%" PRIu16 " ] Software image integrity check failed"; break;
-        case SoftwareUpdate::kStatus_Abort                                              : fmt = "[ SWU(%08" PRIX32 "):%" PRIu16 " ] Software image query aborted"; break;
-        case SoftwareUpdate::kStatus_Retry                                              : fmt = "[ SWU(%08" PRIX32 "):%" PRIu16 " ] Retry software image query"; break;
-        default                                                                         : fmt = "[ SWU(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        case SoftwareUpdate::kStatus_NoUpdateAvailable                     : errorMsg = "No software update available"; break;
+        case SoftwareUpdate::kStatus_UpdateFailed                          : errorMsg = "Software update failed"; break;
+        case SoftwareUpdate::kStatus_InvalidInstructions                   : errorMsg = "Invalid software image download instructions"; break;
+        case SoftwareUpdate::kStatus_DownloadFailed                        : errorMsg = "Software image download failed"; break;
+        case SoftwareUpdate::kStatus_IntegrityCheckFailed                  : errorMsg = "Software image integrity check failed"; break;
+        case SoftwareUpdate::kStatus_Abort                                 : errorMsg = "Software image query aborted"; break;
+        case SoftwareUpdate::kStatus_Retry                                 : errorMsg = "Retry software image query"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
     case kWeaveProfile_Tunneling:
+        profileName = "WeaveTunnel";
         switch (statusCode)
 	{
 #if WEAVE_CONFIG_ENABLE_TUNNELING
-	case WeaveTunnel::kStatusCode_TunnelOpenFail                                    : fmt = "[ WeaveTunnel(%08" PRIX32 "):%" PRIu16 " ] Tunnel open failed"; break;
-	case WeaveTunnel::kStatusCode_TunnelCloseFail                                   : fmt = "[ WeaveTunnel(%08" PRIX32 "):%" PRIu16 " ] Tunnel close failed"; break;
-	case WeaveTunnel::kStatusCode_TunnelRouteUpdateFail                             : fmt = "[ WeaveTunnel(%08" PRIX32 "):%" PRIu16 " ] Tunnel route update failed"; break;
-	case WeaveTunnel::kStatusCode_TunnelReconnectFail                               : fmt = "[ WeaveTunnel(%08" PRIX32 "):%" PRIu16 " ] Tunnel reconnect failed"; break;
+	case WeaveTunnel::kStatusCode_TunnelOpenFail                       : errorMsg = "Tunnel open failed"; break;
+	case WeaveTunnel::kStatusCode_TunnelCloseFail                      : errorMsg = "Tunnel close failed"; break;
+	case WeaveTunnel::kStatusCode_TunnelRouteUpdateFail                : errorMsg = "Tunnel route update failed"; break;
+	case WeaveTunnel::kStatusCode_TunnelReconnectFail                  : errorMsg = "Tunnel reconnect failed"; break;
 #endif
-	default                                                                         : fmt = "[ WeaveTunnel(%08" PRIX32 "):%" PRIu16 " ]"; break;
+	default                                                            : errorMsg = ""; break;
 	}
         break;
 
     case kWeaveProfile_StatusReport_Deprecated:
+        profileName = "Security";
         switch (statusCode)
         {
-        default                                                                         : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ]"; break;
+        default                                                            : errorMsg = ""; break;
         }
         break;
 
@@ -342,10 +358,18 @@
 
     }
 
-    if (fmt == NULL)
-        fmt = "[ %08" PRIX32 ":%" PRIu16 " ]";
+    if (profileName != NULL)
+    {
+        snprintf(sErrorStr, sizeof(sErrorStr) - 2, fmt, profileName, profileId, statusCode, errorMsg);
+    }
+    else
+    {
+        if (fmt == NULL)
+            fmt = "[ %08" PRIX32 ":%" PRIu16 " ]";
 
-    snprintf(sErrorStr, sizeof(sErrorStr) - 2, fmt, profileId, statusCode);
+        snprintf(sErrorStr, sizeof(sErrorStr) - 2, fmt, profileId, statusCode);
+    }
+
     sErrorStr[sizeof(sErrorStr) - 1] = 0;
     return sErrorStr;
 }
diff --git a/src/lib/support/crypto/CTRMode.cpp b/src/lib/support/crypto/CTRMode.cpp
index 120503b..e93b1ef 100644
--- a/src/lib/support/crypto/CTRMode.cpp
+++ b/src/lib/support/crypto/CTRMode.cpp
@@ -38,9 +38,11 @@
 namespace Crypto {
 
 template <class BlockCipher>
-CTRMode<BlockCipher>::CTRMode()
+CTRMode<BlockCipher>::CTRMode() : mBlockCipher()
 {
-    memset(this, 0, sizeof(*this));
+    mMsgIndex = 0;
+    memset(Counter, 0, sizeof(Counter));
+    ClearSecretData(mEncryptedCounter, sizeof(mEncryptedCounter));
 }
 
 template <class BlockCipher>
diff --git a/src/lib/support/crypto/DRBG.cpp b/src/lib/support/crypto/DRBG.cpp
index 05b2b15..f0346dc 100644
--- a/src/lib/support/crypto/DRBG.cpp
+++ b/src/lib/support/crypto/DRBG.cpp
@@ -36,9 +36,12 @@
 namespace Crypto {
 
 template <class BlockCipher>
-CTR_DRBG<BlockCipher>::CTR_DRBG()
+CTR_DRBG<BlockCipher>::CTR_DRBG() : mBlockCipher()
 {
-    memset(this, 0, sizeof(*this));
+    mEntropyFunct = NULL;
+    mReseedCounter = 0;
+    mEntropyFunct = 0;
+    memset(mCounter, 0, kBlockLength);
 }
 
 template <class BlockCipher>
diff --git a/src/system/SystemLayer.cpp b/src/system/SystemLayer.cpp
index 8b40038..a7b67eb 100644
--- a/src/system/SystemLayer.cpp
+++ b/src/system/SystemLayer.cpp
@@ -555,24 +555,22 @@
 /**
  *  Prepare the sets of file descriptors for @p select() to work with.
  *
- *  @param[out] aSetSize        The range of file descriptors in the file descriptor set.
- *  @param[in]  aReadSet        A pointer to the set of readable file descriptors.
- *  @param[in]  aWriteSet       A pointer to the set of writable file descriptors.
- *  @param[in]  aExceptionSet   A pointer to the set of file descriptors with errors.
- *  @param[in]  aSleepTime      A reference to the maximum sleep time.
+ *  @param[in,out]  pollFDs     The fd set which is going to be polled
+ *  @param[in,out]  numPollFDs  The number of fds in the fd set
+ *  @param[in]      timeoutMS   A reference to the maximum sleep time.
  */
-void Layer::PrepareSelect(int& aSetSize, fd_set* aReadSet, fd_set* aWriteSet, fd_set* aExceptionSet, struct timeval& aSleepTime)
+void Layer::PrepareSelect(struct pollfd * pollFDs, int& numPollFDs, int& timeoutMS)
 {
     if (this->State() != kLayerState_Initialized)
         return;
 
-    if (this->mWakePipeIn + 1 > aSetSize)
-        aSetSize = this->mWakePipeIn + 1;
-
-    FD_SET(this->mWakePipeIn, aReadSet);
+    struct pollfd & event = pollFDs[numPollFDs++];
+    event.fd = this->mWakePipeIn;
+    event.events = POLLIN;
+    event.revents = 0;
 
     const Timer::Epoch kCurrentEpoch = Timer::GetCurrentEpoch();
-    Timer::Epoch lAwakenEpoch = kCurrentEpoch + static_cast<Timer::Epoch>(aSleepTime.tv_sec) * 1000 + aSleepTime.tv_usec / 1000;
+    Timer::Epoch lAwakenEpoch = kCurrentEpoch + timeoutMS;
 
     for (size_t i = 0; i < Timer::sPool.Size(); i++)
     {
@@ -592,8 +590,7 @@
     }
 
     const Timer::Epoch kSleepTime = lAwakenEpoch - kCurrentEpoch;
-    aSleepTime.tv_sec = kSleepTime / 1000;
-    aSleepTime.tv_usec = (kSleepTime % 1000) * 1000;
+    timeoutMS = kSleepTime;
 }
 
 /**
@@ -607,30 +604,25 @@
  *  I/O related to the old incarnation of the endpoint, not the current one. Saving the pending I/O state in each endpoint before
  *  acting on it allows the endpoint code to clear the I/O flags in the event of a close, thus avoiding any confusion.
  *
- *  @param[in]    aSetSize          The return value of the select call.
- *  @param[in]    aReadSet          A pointer to the set of read file descriptors.
- *  @param[in]    aWriteSet         A pointer to the set of write file descriptors.
- *  @param[in]    aExceptionSet     A pointer to the set of file descriptors with errors.
- *
+ *  @param[in]    pollFDs     The result of polled FDs
+ *  @param[in]    numPollFDs  The number of fds in the fd set
  */
-void Layer::HandleSelectResult(int aSetSize, fd_set* aReadSet, fd_set* aWriteSet, fd_set* aExceptionSet)
+void Layer::HandleSelectResult(const struct pollfd * pollFDs, int numPollFDs)
 {
     pthread_t lThreadSelf;
 
     if (this->State() != kLayerState_Initialized)
         return;
 
-    if (aSetSize < 0)
-        return;
-
 #if WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
     lThreadSelf = pthread_self();
 #endif // WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
 
-    if (aSetSize > 0)
+    for (int i = 0; i < numPollFDs; ++i)
     {
+        const struct pollfd & event = pollFDs[i];
         // If we woke because of someone writing to the wake pipe, clear the contents of the pipe before returning.
-        if (FD_ISSET(this->mWakePipeIn, aReadSet))
+        if (event.fd == this->mWakePipeIn && event.revents != 0)
         {
             while (true)
             {
diff --git a/src/system/SystemLayer.h b/src/system/SystemLayer.h
index 148ed5e..668fec6 100644
--- a/src/system/SystemLayer.h
+++ b/src/system/SystemLayer.h
@@ -31,7 +31,7 @@
 
 // Include dependent headers
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-#include <sys/select.h>
+#include <poll.h>
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
 #if WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
@@ -156,8 +156,8 @@
     Error ScheduleWork(TimerCompleteFunct aComplete, void* aAppState);
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-    void PrepareSelect(int& aSetSize, fd_set* aReadSet, fd_set* aWriteSet, fd_set* aExceptionSet, struct timeval& aSleepTime);
-    void HandleSelectResult(int aSetSize, fd_set* aReadSet, fd_set* aWriteSet, fd_set* aExceptionSet);
+    void PrepareSelect(struct pollfd * pollFDs, int& numPollFDs, int& timeoutMS);
+    void HandleSelectResult(const struct pollfd * pollFDs, int numPollFDs);
     void WakeSelect(void);
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
diff --git a/src/system/SystemPacketBuffer.cpp b/src/system/SystemPacketBuffer.cpp
index c50d49b..afca4ef 100644
--- a/src/system/SystemPacketBuffer.cpp
+++ b/src/system/SystemPacketBuffer.cpp
@@ -251,12 +251,12 @@
  */
 PacketBuffer* PacketBuffer::DetachTail()
 {
-    PacketBuffer& lReturn = *static_cast<PacketBuffer*>(this->next);
+    PacketBuffer* lReturn = static_cast<PacketBuffer*>(this->next);
 
     this->next = NULL;
     this->tot_len = this->len;
 
-    return &lReturn;
+    return lReturn;
 }
 
 /**
diff --git a/src/test-apps/AndroidTest.cpp b/src/test-apps/AndroidTest.cpp
index f021753..bd714e7 100644
--- a/src/test-apps/AndroidTest.cpp
+++ b/src/test-apps/AndroidTest.cpp
@@ -253,22 +253,21 @@
 
 void ServiceNetwork(struct timeval sleepTime)
 {
-    fd_set readFDs, writeFDs, exceptFDs;
-    int numFDs = 0;
-
-    FD_ZERO(&readFDs);
-    FD_ZERO(&writeFDs);
-    FD_ZERO(&exceptFDs);
+    int sleepTime = aSleepTime.tv_usec / 1000 + aSleepTime.tv_sec * 1000;
+    struct pollfd pollFDs[WEAVE_CONFIG_MAX_POLL_FDS];
+    int numPollFDs = 0;
 
     if (Inet.State == InetLayer::kState_Initialized)
-        Inet.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs);
+        Inet.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 
-    int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &sleepTime);
-    if (selectRes < 0)
-        printf("select failed: %ld\n", (long)(errno));
+    int pollRes = poll(pollFDs, numPollFDs, sleepTime);
+    if (pollRes < 0)
+    {
+        printf("poll failed: %s\n", ErrorStr(MapErrorPOSIX(errno)));
+    }
 
-    if (selectRes > 0 && Inet.State == InetLayer::kState_Initialized)
-        Inet.HandleIO(&readFDs, &writeFDs, &exceptFDs);
+    if (pollRes > 0 && Inet.State == InetLayer::kState_Initialized)
+        Inet.HandleSelectResult(pollFDs, numPollFDs);
 }
 
 uint64_t Now()
diff --git a/src/test-apps/Makefile.am b/src/test-apps/Makefile.am
index 7623112..6bdf850 100644
--- a/src/test-apps/Makefile.am
+++ b/src/test-apps/Makefile.am
@@ -1041,6 +1041,7 @@
     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       \
+    happy/tests/standalone/wdmNext/test_weave_wdm_next_disable_notify_01.py       \
     $(NULL)
 
 endif # WEAVE_RUN_HAPPY_WDM
diff --git a/src/test-apps/MockSourceTraits.h b/src/test-apps/MockSourceTraits.h
index 6b401f3..d722fcf 100644
--- a/src/test-apps/MockSourceTraits.h
+++ b/src/test-apps/MockSourceTraits.h
@@ -156,7 +156,7 @@
     uint32_t tae[10];
 
     // weave.common.StringRef is implemented as a union
-    char *tag_string = "stringreftest";
+    char tag_string[20] = "stringreftest";
     uint16_t tag_ref;
     bool tag_use_ref;
     uint32_t tai_stageditem;
@@ -186,7 +186,7 @@
     uint32_t tat;
     int32_t tau;
     bool tav;
-    char *taw = "boxedstring";
+    char taw[20] = "boxedstring";
     // boxed float
     int16_t tax;
 
diff --git a/src/test-apps/MockWdmSubscriptionInitiator.cpp b/src/test-apps/MockWdmSubscriptionInitiator.cpp
index 77d311c..8ed495d 100644
--- a/src/test-apps/MockWdmSubscriptionInitiator.cpp
+++ b/src/test-apps/MockWdmSubscriptionInitiator.cpp
@@ -252,6 +252,8 @@
         kTestCase_IncompatibleVersionedCommandRequest = 9,
 
         kTestCase_TestUpdatableTraits = 10,
+
+        kTestCase_TestDisableSendingNotifies = 11,
     };
 
     enum
@@ -481,6 +483,10 @@
     case kTestCase_TestUpdatableTraits:
         WeaveLogDetail(DataManagement, "kTestCase_TestUpdatableTraits");
         break;
+
+    case kTestCase_TestDisableSendingNotifies:
+        WeaveLogDetail(DataManagement, "kTestCase_TestDisableSendingNotifies");
+        break;
     default:
         mTestCaseId = kTestCase_TestTrait;
         WeaveLogDetail(DataManagement, "kTestCase_TestTrait");
@@ -565,6 +571,7 @@
     {
     case kTestCase_IntegrationTrait:
     case kTestCase_RejectIncomingSubscribeRequest:
+    case kTestCase_TestDisableSendingNotifies:
         mTraitPaths[0].mTraitDataHandle = mTraitHandleSet[kLocaleSettingsSinkIndex];
         mTraitPaths[0].mPropertyPathHandle = kRootPropertyPathHandle;
 
@@ -1061,6 +1068,7 @@
         {
         case kTestCase_IntegrationTrait:
         case kTestCase_RejectIncomingSubscribeRequest:
+        case kTestCase_TestDisableSendingNotifies:
             initiator->AddNewVersion(initiator->kLocaleSettingsSinkIndex);
             initiator->AddNewVersion(initiator->kApplicationKeysTraitSinkIndex);
             break;
@@ -1515,6 +1523,11 @@
             initiator->mLocaleCapabilitiesDataSource.Mutate();
             SubscriptionEngine::GetInstance()->GetNotificationEngine()->Run();
             break;
+        case kTestCase_TestDisableSendingNotifies:
+            initiator->mLocaleCapabilitiesDataSource.Mutate();
+            SubscriptionEngine::GetInstance()->GetNotificationEngine()->DisableNotifications();
+            SubscriptionEngine::GetInstance()->GetNotificationEngine()->Run();
+            break;
         case kTestCase_TestTrait:
             initiator->mTestATraitDataSource0.Mutate();
             initiator->mTestATraitDataSource1.Mutate();
diff --git a/src/test-apps/MockWdmSubscriptionResponder.cpp b/src/test-apps/MockWdmSubscriptionResponder.cpp
index df682aa..5b85853 100644
--- a/src/test-apps/MockWdmSubscriptionResponder.cpp
+++ b/src/test-apps/MockWdmSubscriptionResponder.cpp
@@ -79,24 +79,6 @@
 static bool gCleanStatus = true;
 static nl::Weave::WRMPConfig gWRMPConfig = { kWRMPInitialRetransTimeoutMsec, kWRMPActiveRetransTimeoutMsec, kWRMPAckTimeoutMsec, kWRMPMaxRetrans };
 
-
-static void TLVPrettyPrinter(const char *aFormat, ...)
-{
-    va_list args;
-
-    va_start(args, aFormat);
-
-    // There is no proper Weave logging routine for us to use here
-    vprintf(aFormat, args);
-
-    va_end(args);
-}
-
-static WEAVE_ERROR DebugPrettyPrint(nl::Weave::TLV::TLVReader & aReader)
-{
-    return nl::Weave::TLV::Debug::Dump(aReader, TLVPrettyPrinter);
-}
-
 nl::Weave::Profiles::DataManagement::SubscriptionEngine * nl::Weave::Profiles::DataManagement::SubscriptionEngine::GetInstance()
 {
     static nl::Weave::Profiles::DataManagement::SubscriptionEngine gWdmSubscriptionEngine;
@@ -1082,9 +1064,7 @@
 
     {
         uint64_t nowMicroSecs, deadline;
-        CommandSender::SendParams sendParams;
-
-        memset(&sendParams, 0, sizeof(sendParams));
+        CommandSender::SendParams sendParams = CommandSender::SendParams();
 
         if (mTestCaseId == kTestCase_ForwardCompatibleVersionedRequest) {
             sendParams.VersionRange.mMaxVersion = 4;
diff --git a/src/test-apps/TestSystemObject.cpp b/src/test-apps/TestSystemObject.cpp
index 3f87f57..16e913d 100644
--- a/src/test-apps/TestSystemObject.cpp
+++ b/src/test-apps/TestSystemObject.cpp
@@ -295,7 +295,7 @@
 void* TestObject::CheckHighWatermarkThread(void* aContext)
 {
     TestContext&        lContext        = *static_cast<TestContext*>(aContext);
-    unsigned int        i;
+    int        i;
     nl::Weave::System::Stats::count_t lNumInUse;
     nl::Weave::System::Stats::count_t lHighWatermark;
 
@@ -359,11 +359,11 @@
 {
     memset(&sPool, 0, sizeof(sPool));
 
-    const unsigned int  kNumObjects     = kPoolSize;
+    const int           kNumObjects     = kPoolSize;
     TestObject*         lObject         = NULL;
     TestContext&        lContext        = *static_cast<TestContext*>(aContext);
     Layer               lLayer;
-    unsigned int        i;
+    int                 i;
     nl::Weave::System::Stats::count_t lNumInUse;
     nl::Weave::System::Stats::count_t lHighWatermark;
 
diff --git a/src/test-apps/TestSystemTimer.cpp b/src/test-apps/TestSystemTimer.cpp
index 7e51ffb..9221847 100644
--- a/src/test-apps/TestSystemTimer.cpp
+++ b/src/test-apps/TestSystemTimer.cpp
@@ -40,7 +40,7 @@
 #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-#include <sys/select.h>
+#include <poll.h>
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
 #include <SystemLayer/SystemError.h>
@@ -57,20 +57,17 @@
 static void ServiceEvents(Layer& aLayer, ::timeval& aSleepTime)
 {
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-    fd_set readFDs, writeFDs, exceptFDs;
-    int numFDs = 0;
-
-    FD_ZERO(&readFDs);
-    FD_ZERO(&writeFDs);
-    FD_ZERO(&exceptFDs);
+    int sleepTime = aSleepTime.tv_usec / 1000 + aSleepTime.tv_sec * 1000;
+    struct pollfd pollFDs[WEAVE_CONFIG_MAX_POLL_FDS];
+    int numPollFDs = 0;
 
     if (aLayer.State() == kLayerState_Initialized)
-        aLayer.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
+        aLayer.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 
-    int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime);
-    if (selectRes < 0)
+    int pollRes = poll(pollFDs, numPollFDs, sleepTime);
+    if (pollRes < 0)
     {
-        printf("select failed: %s\n", ErrorStr(MapErrorPOSIX(errno)));
+        printf("poll failed: %s\n", ErrorStr(MapErrorPOSIX(errno)));
         return;
     }
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
@@ -78,7 +75,7 @@
     if (aLayer.State() == kLayerState_Initialized)
     {
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-        aLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+        aLayer.HandleSelectResult(pollFDs, numPollFDs);
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
 #if WEAVE_SYSTEM_CONFIG_USE_LWIP
diff --git a/src/test-apps/TestTLV.cpp b/src/test-apps/TestTLV.cpp
index ff280ad..9a4431a 100644
--- a/src/test-apps/TestTLV.cpp
+++ b/src/test-apps/TestTLV.cpp
@@ -580,11 +580,12 @@
 
         TestNext<TLVReader>(inSuite, reader2);
 
-        TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), (float)17.9);
+        TestGet<TLVReader, float>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), 17.9f);
+        TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), 17.9f);
 
         TestNext<TLVReader>(inSuite, reader2);
 
-        TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536), (double)17.9);
+        TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536), 17.9);
 
         TestEndAndCloseContainer(inSuite, reader, reader2);
     }
@@ -2946,11 +2947,12 @@
 
         TestNext<TLVReader>(inSuite, reader2);
 
-        TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), (float)17.9);
+        TestGet<TLVReader, float>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), 17.9f);
+        TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), 17.9f);
 
         TestNext<TLVReader>(inSuite, reader2);
 
-        TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536), (double)17.9);
+        TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536), 17.9);
 
         TestEndAndCloseContainer(inSuite, reader, reader2);
     }
@@ -2974,6 +2976,11 @@
     err = reader.Get(val);
     NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
 
+    // Get(float&)
+    float numF;
+    err = reader.Get(numF);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
+
     // Get(double&)
     double numD;
     err = reader.Get(numD);
@@ -3020,6 +3027,38 @@
     NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
     free((void *)data);
 }
+
+/**
+ *  Test that Weave TLV reader returns an error when a read is requested that
+ *  would truncate the output.
+ */
+void TestWeaveTLVReaderTruncatedReads(nlTestSuite * inSuite)
+{
+    uint8_t buf[2048];
+    TLVWriter writer;
+    TLVReader reader;
+
+    WEAVE_ERROR err;
+    float outF;
+
+    // Setup: Write some values into the buffer
+    writer.Init(buf, sizeof(buf));
+    writer.ImplicitProfileId = TestProfile_2;
+
+    err = writer.Put(AnonymousTag, double(12.5));
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+
+    // Test reading values from the buffer
+    reader.Init(buf, sizeof(buf));
+
+    TestNext<TLVReader>(inSuite, reader);
+
+    TestGet<TLVReader, double>(inSuite, reader, kTLVType_FloatingPointNumber, AnonymousTag, 12.5);
+
+    err = reader.Get(outF);
+    NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
+}
+
 /**
  *  Test Weave TLV Reader in a use case
  */
@@ -3046,7 +3085,7 @@
 
     TestNext<TLVReader>(inSuite, reader);
 
-    TestGet<TLVReader, double>(inSuite, reader, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_1, 4000000000ULL), (float) 1.0);
+    TestGet<TLVReader, float>(inSuite, reader, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_1, 4000000000ULL), (float) 1.0);
 }
 
 void TestWeaveTLVReader_NextOverContainer_ProcessElement(nlTestSuite *inSuite, TLVReader& reader, void *context)
@@ -3147,6 +3186,8 @@
 
     TestWeaveTLVReaderErrorHandling(inSuite);
 
+    TestWeaveTLVReaderTruncatedReads(inSuite);
+
     TestWeaveTLVReaderInPractice(inSuite);
 
     TestWeaveTLVReader_NextOverContainer(inSuite);
diff --git a/src/test-apps/TestWdmUpdateServer.cpp b/src/test-apps/TestWdmUpdateServer.cpp
index eddb2de..1e45ca3 100644
--- a/src/test-apps/TestWdmUpdateServer.cpp
+++ b/src/test-apps/TestWdmUpdateServer.cpp
@@ -265,7 +265,6 @@
     PacketBuffer * pBuf = NULL;
     UpdateRequest::Parser update;
     Weave::TLV::TLVReader reader;
-    bool isDataListPresent                                             = false;
     bool existFailure                                                  = false;
     uint32_t numDataElements                                           = 0;
     uint32_t maxPayloadSize                                            = 0;
@@ -297,14 +296,9 @@
     {
         DataList::Parser dataList;
         err = update.GetDataList(&dataList);
-        if (WEAVE_NO_ERROR == err)
+        if (WEAVE_END_OF_TLV == err)
         {
-            isDataListPresent = true;
-        }
-        else if (WEAVE_END_OF_TLV == err)
-        {
-            isDataListPresent = false;
-            err               = WEAVE_NO_ERROR;
+            err = WEAVE_NO_ERROR;
         }
         SuccessOrExit(err);
 
diff --git a/src/test-apps/TestWeaveTunnel.h b/src/test-apps/TestWeaveTunnel.h
index 23b2fb6..1e8880b 100644
--- a/src/test-apps/TestWeaveTunnel.h
+++ b/src/test-apps/TestWeaveTunnel.h
@@ -83,6 +83,7 @@
     kTestNum_TestTunnelRestrictedRoutingOnStandaloneTunnelOpen  = 27,
     kTestNum_TestTunnelTCPIdle                                  = 28,
     kTestNum_TestTunnelPersistCASESession                       = 29,
+    kTestNum_TestTunneledPacketCapture                          = 30,
 };
 
 #endif // WEAVE_CONFIG_ENABLE_TUNNELING
diff --git a/src/test-apps/TestWeaveTunnelBR.cpp b/src/test-apps/TestWeaveTunnelBR.cpp
index 8a8486e..1432bdb 100644
--- a/src/test-apps/TestWeaveTunnelBR.cpp
+++ b/src/test-apps/TestWeaveTunnelBR.cpp
@@ -57,6 +57,12 @@
 #define NL_PATH_PROCNET_IPV6_ROUTE     "/proc/net/ipv6_route"
 #endif /* NL_PATH_PROCNET_IPV6_ROUTE */
 
+const nl::Weave::ExchangeContext::Timeout kResponseTimeoutMsec = 10000;
+const nl::Weave::ExchangeContext::Timeout kWRMPActiveRetransTimeoutMsec = 3000;
+const nl::Weave::ExchangeContext::Timeout kWRMPInitialRetransTimeoutMsec = 3000;
+const uint16_t kWRMPMaxRetrans = 3;
+const uint16_t kWRMPAckTimeoutMsec = 200;
+
 static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
 static bool HandleNonOptionArgs(const char *progName, int argc, char *argv[]);
 static void
@@ -79,6 +85,14 @@
                                      uint8_t msgType, PacketBuffer *payload);
 static void ResetReconnectTimeout(System::Layer* aSystemLayer, void* aAppState, System::Error aError);
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+static void MessageLayerPacketCaptureHandler(uint8_t *msgBuf, uint16_t msgLen, WeaveMessageInfo *msgInfo);
+
+static WEAVE_ERROR SendMessageForCapture(nl::Weave::Binding* binding);
+static void BindingEventCallback (void * const apAppState, const nl::Weave::Binding::EventType aEvent,
+        const nl::Weave::Binding::InEventParam & aInParam, nl::Weave::Binding::OutEventParam & aOutParam);
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 static int AddDeleteIPv4Address(InterfaceId intf, const char *ipAddr, bool isAdd);
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
@@ -104,6 +118,8 @@
 uint64_t gReconnectResetArmTime = 0;
 bool gtestDataSent = false;
 
+static nl::Weave::WRMPConfig gWRMPConfig = { kWRMPInitialRetransTimeoutMsec, kWRMPActiveRetransTimeoutMsec, kWRMPAckTimeoutMsec, kWRMPMaxRetrans };
+
 #if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
 bool gUseServiceDir = false;
 ServiceDirectory::WeaveServiceManager gServiceMgr;
@@ -2726,6 +2742,91 @@
 }
 #endif // WEAVE_CONFIG_TUNNEL_ENABLE_TCP_IDLE_CALLBACK
 
+
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+/**
+ * Test to capture a sent Tunneled Weave message.
+ * Binding API used to indicate intent to capture.
+ * Message Capture Handler receives captured message from WeaveMessageLayer.
+ */
+
+static void TestTunneledPacketCapture(nlTestSuite *inSuite, void *inContext)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    Done = false;
+    gTestSucceeded = false;
+    // Set a longer duration for the queueing test. 3 times the default test
+    // duration(~15 seconds) is sufficient for the completion of this test with
+    // close to 100% confidence.
+    gMaxTestDurationMillisecs = (DEFAULT_TEST_DURATION_MILLISECS * 3);
+    gCurrTestNum = kTestNum_TestTunneledPacketCapture;
+    gTestStartTime = Now();
+
+#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
+    if (gUseServiceDir)
+    {
+        err = gTunAgent.Init(&Inet, &ExchangeMgr, gDestNodeId,
+                            gAuthMode, &gServiceMgr);
+    }
+    else
+#endif
+    {
+        err = gTunAgent.Init(&Inet, &ExchangeMgr, gDestNodeId, gDestAddr,
+                            gAuthMode);
+    }
+
+
+    gTunAgent.OnServiceTunStatusNotify = WeaveTunnelOnStatusNotifyHandlerCB;
+
+    SuccessOrExit(err);
+
+    ExchangeMgr.MessageLayer->SetMessageLayerPktCaptureHandler(MessageLayerPacketCaptureHandler);
+
+    err = gTunAgent.StartServiceTunnel();
+    SuccessOrExit(err);
+
+    while (!Done)
+    {
+        struct timeval sleepTime;
+        sleepTime.tv_sec = TEST_SLEEP_TIME_WITHIN_LOOP_SECS;
+        sleepTime.tv_usec = TEST_SLEEP_TIME_WITHIN_LOOP_MICROSECS;
+
+        ServiceNetwork(sleepTime);
+
+        if (Now() < gTestStartTime + gMaxTestDurationMillisecs * System::kTimerFactor_micro_per_milli)
+        {
+            if (gTestSucceeded)
+            {
+                Done = true;
+            }
+            else
+            {
+                continue;
+            }
+        }
+        else // Time's up
+        {
+            gTestSucceeded = false;
+            Done = true;
+        }
+
+        if (Done)
+        {
+
+            gTunAgent.StopServiceTunnel(WEAVE_NO_ERROR);
+        }
+    }
+
+exit:
+
+    NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, gTestSucceeded == true);
+
+    gTunAgent.Shutdown();
+}
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
 void HandleTunnelTestResponse(ExchangeContext *ec, const IPPacketInfo *pktInfo,
                               const WeaveMessageInfo *msgInfo, uint32_t profileId,
                               uint8_t msgType, PacketBuffer *payload)
@@ -2840,6 +2941,74 @@
 }
 #endif // WEAVE_CONFIG_TUNNEL_ENABLE_TCP_IDLE_CALLBACK
 
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+WEAVE_ERROR SendMessageForCapture(nl::Weave::Binding* binding)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    nl::Weave::ExchangeContext* ec = NULL;
+
+    err = binding->NewExchangeContext(ec);
+    SuccessOrExit(err);
+
+    WeaveLogDetail(WeaveTunnel, "Sending Echo Message for Capture\n");
+    err = SendTunnelTestMessage(ec, kWeaveProfile_Echo,
+                                kEchoMessageType_EchoRequest,
+                                0);
+    SuccessOrExit(err);
+
+exit:
+    return err;
+
+}
+
+void MessageLayerPacketCaptureHandler(uint8_t *msgBuf, uint16_t msgLen, WeaveMessageInfo *msgInfo)
+{
+    WeaveLogDetail(WeaveTunnel, "Tunneled packet received by capture handler\n");
+
+    gTestSucceeded = true;
+}
+
+void
+BindingEventCallback(
+    void* const apAppState,
+    const nl::Weave::Binding::EventType aEventType,
+    const nl::Weave::Binding::InEventParam& aInParam,
+    nl::Weave::Binding::OutEventParam& aOutParam)
+{
+
+    nl::Weave::Binding* binding = aInParam.Source;
+
+    // TODO: Failure events need correct handling when they occur
+    switch (aEventType)
+    {
+        case nl::Weave::Binding::kEvent_PrepareRequested:
+        {
+            // Nothing to do here, since the binding preperation is done in
+            // Addbinding
+            break;
+        }
+        case nl::Weave::Binding::kEvent_BindingReady:
+        {
+            WeaveLogDetail(WeaveTunnel, "Binding Ready: Send for Capture\n");
+            /* Send the message for the binding that is ready
+             * in the un-cached binding model */
+            (void)SendMessageForCapture(binding);
+            break;
+        }
+        case nl::Weave::Binding::kEvent_PrepareFailed:
+        case nl::Weave::Binding::kEvent_BindingFailed:
+        {
+            break;
+        }
+        default:
+            // All unhandled events must be delivered to the binding's default
+            // event handler.
+            nl::Weave::Binding::DefaultEventHandler(
+                apAppState, aEventType, aInParam, aOutParam);
+    }
+}
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+
 void
 WeaveTunnelOnStatusNotifyHandlerCB(WeaveTunnelConnectionMgr::TunnelConnNotifyReasons reason,
                                    WEAVE_ERROR aErr, void *appCtxt)
@@ -3233,6 +3402,36 @@
         }
 
         break;
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+      case kTestNum_TestTunneledPacketCapture:
+        if (reason == WeaveTunnelConnectionMgr::kStatus_TunPrimaryUp)
+        {
+            // Tunnel established; Formulate a message for capture and send it.
+
+            WeaveLogDetail(WeaveTunnel, "Tunnel Up for sending Capture message\n");
+            nl::Weave::Binding *newBinding = ExchangeMgr.NewBinding(BindingEventCallback, NULL);
+            VerifyOrExit(NULL != newBinding, err = WEAVE_ERROR_NO_MEMORY);
+
+            {
+                Binding::Configuration bindingConfig = newBinding->BeginConfiguration()
+                    .Target_NodeId(gDestNodeId)
+                    .TargetAddress_WeaveFabric(kWeaveSubnetId_Service)
+                    .Transport_UDP_WRM()
+                    //.Transport_UDP()
+                    .Transport_DefaultWRMPConfig(gWRMPConfig)
+                    .Exchange_ResponseTimeoutMsec(kResponseTimeoutMsec)
+                    .Security_None();
+
+                WeaveLogDetail(WeaveTunnel, "Set Binding flag for Capture\n");
+                bindingConfig.CaptureTxMessage();
+
+                err = bindingConfig.PrepareBinding();
+                SuccessOrExit(err);
+            }
+        }
+
+        break;
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
 
       default:
 
@@ -3285,6 +3484,9 @@
     NL_TEST_DEF("TestTunnelResetReconnectBackoffImmediately", TestTunnelResetReconnectBackoffImmediately),
     NL_TEST_DEF("TestTunnelResetReconnectBackoffRandomized", TestTunnelResetReconnectBackoffRandomized),
     NL_TEST_DEF("TestTunnelNoStatusReportResetReconnectBackoff", TestTunnelNoStatusReportResetReconnectBackoff),
+#if WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
+    NL_TEST_DEF("TestTunneledPacketCapture", TestTunneledPacketCapture),
+#endif // WEAVE_CONFIG_ENABLE_MESSAGE_CAPTURE
 #if WEAVE_CONFIG_TUNNEL_ENABLE_TCP_IDLE_CALLBACK
     NL_TEST_DEF("TestTunnelTCPIdle", TestTunnelTCPIdle),
 #endif // WEAVE_CONFIG_TUNNEL_ENABLE_TCP_IDLE_CALLBACK
diff --git a/src/test-apps/TestWeaveTunnelCASEPersistClient.cpp b/src/test-apps/TestWeaveTunnelCASEPersistClient.cpp
index a38735b..1f45199 100644
--- a/src/test-apps/TestWeaveTunnelCASEPersistClient.cpp
+++ b/src/test-apps/TestWeaveTunnelCASEPersistClient.cpp
@@ -62,12 +62,14 @@
 
 static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
 static bool HandleNonOptionArgs(const char *progName, int argc, char *argv[]);
+#if WEAVE_CONFIG_PERSIST_CONNECTED_SESSION
 static void HandleLoadPersistedTunnelCASESession(nl::Weave::WeaveConnection *con);
-static void HandleSessionPersistOnTunnelClosure(nl::Weave::WeaveConnection *con);
-static WEAVE_ERROR RestorePersistedTunnelCASESession(nl::Weave::WeaveConnection *con);
-static WEAVE_ERROR SuspendAndPersistTunnelCASESession(nl::Weave::WeaveConnection *con);
 static bool IsPersistentTunnelSessionPresent(uint64_t peerNodeId);
+static WEAVE_ERROR RestorePersistedTunnelCASESession(nl::Weave::WeaveConnection *con);
+#endif
 
+static void HandleSessionPersistOnTunnelClosure(nl::Weave::WeaveConnection *con);
+static WEAVE_ERROR SuspendAndPersistTunnelCASESession(nl::Weave::WeaveConnection *con);
 static void
 WeaveTunnelOnStatusNotifyHandlerCB(WeaveTunnelConnectionMgr::TunnelConnNotifyReasons reason,
                                    WEAVE_ERROR aErr, void *appCtxt);
@@ -326,6 +328,7 @@
     return err;
 }
 
+#if WEAVE_CONFIG_PERSIST_CONNECTED_SESSION
 WEAVE_ERROR
 RestorePersistedTunnelCASESession(nl::Weave::WeaveConnection *con)
 {
@@ -397,6 +400,14 @@
     }
 }
 
+bool IsPersistentTunnelSessionPresent(uint64_t peerNodeId)
+{
+    const char * persistentTunnelSessionPath = PERSISTENT_TUNNEL_SESSION_PATH;
+
+    return (access(persistentTunnelSessionPath, F_OK) != -1);
+}
+#endif // WEAVE_CONFIG_PERSIST_CONNECTED_SESSION
+
 void HandleSessionPersistOnTunnelClosure(nl::Weave::WeaveConnection *con)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
@@ -408,13 +419,6 @@
         printf("Suspending and persisting Tunnel CASE Session failed with Weave error: %d\n", err);
     }
 }
-
-bool IsPersistentTunnelSessionPresent(uint64_t peerNodeId)
-{
-    const char * persistentTunnelSessionPath = PERSISTENT_TUNNEL_SESSION_PATH;
-
-    return (access(persistentTunnelSessionPath, F_OK) != -1);
-}
 #endif // WEAVE_CONFIG_ENABLE_TUNNELING
 
 int main(int argc, char *argv[])
diff --git a/src/test-apps/ToolCommon.cpp b/src/test-apps/ToolCommon.cpp
index bc9aa69..31fefe3 100644
--- a/src/test-apps/ToolCommon.cpp
+++ b/src/test-apps/ToolCommon.cpp
@@ -92,7 +92,7 @@
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 #include <arpa/inet.h>
-#include <sys/select.h>
+#include <poll.h>
 #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
 
 #if WEAVE_SYSTEM_CONFIG_USE_LWIP
@@ -1013,29 +1013,27 @@
         }
     }
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-    fd_set readFDs, writeFDs, exceptFDs;
-    int numFDs = 0;
-
-    FD_ZERO(&readFDs);
-    FD_ZERO(&writeFDs);
-    FD_ZERO(&exceptFDs);
+    int sleepTime = aSleepTime.tv_usec / 1000 + aSleepTime.tv_sec * 1000;
+    struct pollfd pollFDs[WEAVE_CONFIG_MAX_POLL_FDS];
+    int numPollFDs = 0;
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
     if (SystemLayer.State() == System::kLayerState_Initialized)
-        SystemLayer.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
+        SystemLayer.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
     if (Inet.State == InetLayer::kState_Initialized)
-        Inet.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
+        Inet.PrepareSelect(pollFDs, numPollFDs, sleepTime);
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
-    int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime);
-    if (selectRes < 0)
+    int pollRes = poll(pollFDs, numPollFDs, sleepTime);
+    if (pollRes < 0)
     {
-        printf("select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno)));
+        printf("poll failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno)));
         return;
     }
+
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
     if (SystemLayer.State() == System::kLayerState_Initialized)
@@ -1046,7 +1044,7 @@
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
-        SystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+        SystemLayer.HandleSelectResult(pollFDs, numPollFDs);
 
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
@@ -1083,7 +1081,7 @@
 
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
-        Inet.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+        Inet.HandleSelectResult(pollFDs, numPollFDs);
 
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
diff --git a/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_disable_notify_01.py b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_disable_notify_01.py
new file mode 100755
index 0000000..19f1c43
--- /dev/null
+++ b/src/test-apps/happy/tests/standalone/wdmNext/test_weave_wdm_next_disable_notify_01.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+
+
+#
+#    Copyright (c) 2021 Google, 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 mutual subscribe between nodes.
+#       F16: Mutual Subscribe: Root path. Null Version. Mutate data in initiator and responder. Publisher in initiator aborts
+#       M20: Stress Mutual Subscribe: Root path. Null Version. Mutate data in initiator and responder. Publisher in initiator aborts
+#
+
+from __future__ import absolute_import
+from __future__ import print_function
+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_disable_notify_01(weave_wdm_next_test_base):
+
+    def test_weave_wdm_next_disable_notify_01(self):
+        wdm_next_args = {}
+
+        wdm_next_args['wdm_option'] = "mutual_subscribe"
+
+        wdm_next_args['total_client_count'] = 1
+        wdm_next_args['final_client_status'] = 3
+        wdm_next_args['timer_client_period'] = 5000
+        wdm_next_args['test_client_iterations'] = 1
+        wdm_next_args['test_client_delay'] = 25000
+        wdm_next_args['enable_client_flip'] = 1
+        wdm_next_args['test_client_case'] = 11 # kTestCase_TestDisableSendingNotifies
+
+        wdm_next_args['total_server_count'] = 1
+        wdm_next_args['final_server_status'] = 4
+        wdm_next_args['timer_server_period'] = 4000
+        wdm_next_args['enable_server_flip'] = 0
+        wdm_next_args['test_server_case'] = 11 # kTestCase_TestDisableSendingNotifies
+
+        wdm_next_args['client_clear_state_between_iterations'] = True
+        wdm_next_args['server_clear_state_between_iterations'] = True
+
+        wdm_next_args['client_log_check'] = [('Client\[0\] \[(ALIVE|CONFM)\] bound mutual subscription is going away', wdm_next_args['test_client_iterations']),
+                                             ('Client->kEvent_OnNotificationProcessed', wdm_next_args['test_client_iterations'] * (wdm_next_args['total_server_count'])),
+                                             ('Handler\[0\] \[(ALIVE|CONFM)\] AbortSubscription Ref\(\d+\)', wdm_next_args['test_client_iterations']),
+                                             ('Client\[0\] moving to \[ FREE\] Ref\(0\)', wdm_next_args['test_client_iterations']),
+                                             ('Disabling notifications', wdm_next_args['test_client_iterations']),
+                                             ('Notify Transmission disabled', wdm_next_args['test_client_iterations']),
+                                             ('Handler\[0\] Moving to \[ FREE\] Ref\(0\)', wdm_next_args['test_client_iterations'])]
+        wdm_next_args['server_log_check'] = [('TimerEventHandler Ref\(\d+\) Timeout', wdm_next_args['test_client_iterations']),
+                                             ('bound mutual subscription is going away', wdm_next_args['test_client_iterations']),
+                                             ('Client\[0\] \[(ALIVE|CONFM)\] TerminateSubscription ', wdm_next_args['test_client_iterations']),
+                                             ('Client\[0\] moving to \[ FREE\] Ref\(0\)', wdm_next_args['test_client_iterations']),
+                                             ('Handler\[0\] Moving to \[ FREE\] Ref\(0\)', wdm_next_args['test_client_iterations'])]
+        wdm_next_args['test_tag'] = self.__class__.__name__[19:].upper()
+        wdm_next_args['test_case_name'] = ['DisableNotify 01: Disable Notify on Mutual Subscribe: Root path. Null Version. Mutate data in initiator and responder. Publisher in initiator aborts']
+        print('test file: ' + self.__class__.__name__)
+        print("weave-wdm-next DisableNotify test")
+        super(test_weave_wdm_next_disable_notify_01, self).weave_wdm_next_test_base(wdm_next_args)
+
+
+
+if __name__ == "__main__":
+    WeaveUtilities.run_unittest()
+
diff --git a/src/tools/weave/Cmd_PrintAccessToken.cpp b/src/tools/weave/Cmd_PrintAccessToken.cpp
new file mode 100644
index 0000000..08d6e39
--- /dev/null
+++ b/src/tools/weave/Cmd_PrintAccessToken.cpp
@@ -0,0 +1,196 @@
+/*
+ *
+ *    Copyright (c) 2022 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
+ *      This file implements the command handler for the 'weave' tool
+ *      that decodes and prints the contents of a Weave access token certificate.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "weave-tool.h"
+#include <Weave/Support/ASN1OID.h>
+#include <Weave/Profiles/security/WeaveSecurityDebug.h>
+#include <Weave/Profiles/security/WeaveAccessToken.h>
+#include <Weave/Support/Base64.h>
+
+using namespace nl::Weave::ASN1;
+using namespace nl::Weave::Profiles::Security;
+
+#define CMD_NAME "weave print-access-token"
+
+static bool HandleNonOptionArgs(const char *progName, int argc, char *argv[]);
+static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
+
+static OptionDef gCmdOptionDefs[] =
+{
+    { "base64", kNoArgument, 'b' },
+    { }
+};
+
+static const char *const gCmdOptionHelp =
+    "   -b, --base64\n"
+    "\n"
+    "       The file containing the TLV should be parsed as base64.\n"
+    "\n"
+    ;
+
+static OptionSet gCmdOptions =
+{
+    HandleOption,
+    gCmdOptionDefs,
+    "COMMAND OPTIONS",
+    gCmdOptionHelp
+};
+static HelpOptions gHelpOptions(
+    CMD_NAME,
+    "Usage: " CMD_NAME " [<options...>] <access-token>\n",
+    WEAVE_VERSION_STRING "\n" COPYRIGHT_STRING,
+    "Print a Weave Access Token certificate.\n"
+    "\n"
+    "ARGUMENTS\n"
+    "\n"
+    "  <access-token>\n"
+    "\n"
+    "       A file containing a Weave Access Token either in raw TLV format (default)\n"
+    "       or in base-64 format with -b option.\n"
+    "\n"
+);
+
+static OptionSet *gCmdOptionSets[] =
+{
+    &gCmdOptions,
+    &gHelpOptions,
+    NULL
+};
+
+static const char *gCertFileName = NULL;
+static bool gUseBase64Decoding = false;
+enum {
+    kNumCerts = 1,
+    kCertBufSize = 1024,
+};
+
+bool Cmd_PrintAccessToken(int argc, char *argv[])
+{
+    bool res = true;
+    WEAVE_ERROR err;
+    WeaveCertificateData *certData;
+    WeaveCertificateSet certSet;
+    uint8_t * accessToken = NULL;
+    uint32_t accessTokenLen = 0;
+    TLVReader reader;
+
+    if (argc == 1)
+    {
+        gHelpOptions.PrintBriefUsage(stderr);
+        ExitNow(res = true);
+    }
+
+    if (!ParseArgs(CMD_NAME, argc, argv, gCmdOptionSets, HandleNonOptionArgs))
+    {
+        ExitNow(res = false);
+    }
+
+    if (!ReadFileIntoMem(gCertFileName, accessToken, accessTokenLen))
+    {
+        ExitNow(res = false);
+    }
+
+    if (gUseBase64Decoding)
+    {
+        uint32_t b64len = accessTokenLen;
+        uint8_t * b64 = accessToken;
+        accessToken = (uint8_t *)malloc(accessTokenLen);
+        if (accessToken == NULL)
+        {
+            fprintf(stderr, "Memory allocation error\n");
+            free(b64);
+            ExitNow(res = false);
+        }
+        accessTokenLen = nl::Base64Decode((const char *)b64, b64len, accessToken);
+        free(b64);
+    }
+
+    reader.Init(accessToken, accessTokenLen);
+    certSet.Init(kNumCerts, kCertBufSize);
+    err = LoadAccessTokenCerts(reader, certSet, 0, certData);
+
+    if (err != WEAVE_NO_ERROR)
+    {
+        fprintf(stderr, "Error reading cert info: %s.\n", nl::ErrorStr(err));
+        ExitNow(res = false);
+    }
+
+    printf("Weave Access Token:\n");
+
+    printf("Weave Certificate:\n");
+
+    PrintCert(stdout, *certData, NULL, 2, true);
+
+    printf("Access Token Private Key omitted\n");
+
+    res = (err == WEAVE_NO_ERROR);
+
+exit:
+    if (accessToken != NULL)
+        free(accessToken);
+    return res;
+}
+
+bool HandleNonOptionArgs(const char *progName, int argc, char *argv[])
+{
+    if (argc == 0)
+    {
+        PrintArgError("%s: Please specify the name of the certificate to be printed.\n", progName);
+        return false;
+    }
+
+    if (argc > 1)
+    {
+        PrintArgError("%s: Unexpected argument: %s\n", progName, argv[1]);
+        return false;
+    }
+
+    gCertFileName = argv[0];
+
+    return true;
+}
+
+bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
+{
+    switch (id)
+    {
+    case 'b':
+        gUseBase64Decoding = true;
+        break;
+
+    default:
+        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
+        return false;
+    }
+
+    return true;
+}
diff --git a/src/tools/weave/Cmd_PrintServiceConfig.cpp b/src/tools/weave/Cmd_PrintServiceConfig.cpp
new file mode 100644
index 0000000..e553ea6
--- /dev/null
+++ b/src/tools/weave/Cmd_PrintServiceConfig.cpp
@@ -0,0 +1,284 @@
+/*
+ *
+ *    Copyright (c) 2022 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
+ *      This file implements the command handler for the 'weave' tool
+ *      that decodes and prints the contents of a service config object.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "weave-tool.h"
+#include <Weave/Support/ASN1OID.h>
+#include <Weave/Profiles/security/WeaveSecurityDebug.h>
+#include <Weave/Profiles/security/WeaveAccessToken.h>
+#include <Weave/Profiles/service-provisioning/ServiceProvisioning.h>
+#include <Weave/Profiles/service-directory/ServiceDirectory.h>
+#include <Weave/Support/Base64.h>
+
+using namespace nl::Weave::ASN1;
+using namespace nl::Weave::Profiles::Security;
+using namespace nl::Weave::TLV;
+using namespace nl::Weave::Profiles::ServiceProvisioning;
+using namespace nl::Weave::Profiles;
+
+#define CMD_NAME "weave print-service-config"
+
+static WEAVE_ERROR PrintServiceHostname(TLVReader &reader);
+static bool HandleNonOptionArgs(const char *progName, int argc, char *argv[]);
+static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
+
+static OptionDef gCmdOptionDefs[] =
+{
+    { "base64", kNoArgument, 'b' },
+    { }
+};
+
+static const char *const gCmdOptionHelp =
+    "   -b, --base64\n"
+    "\n"
+    "       The file containing the TLV should be parsed as base64.\n"
+    "\n"
+    ;
+
+static OptionSet gCmdOptions =
+{
+    HandleOption,
+    gCmdOptionDefs,
+    "COMMAND OPTIONS",
+    gCmdOptionHelp
+};
+static HelpOptions gHelpOptions(
+    CMD_NAME,
+    "Usage: " CMD_NAME " [<options...>] <service-config-file>\n",
+    WEAVE_VERSION_STRING "\n" COPYRIGHT_STRING,
+    "Print a service config object.\n"
+    "\n"
+    "ARGUMENTS\n"
+    "\n"
+    "  <service-config-file>\n"
+    "\n"
+    "       A file containing a service config object either in binary (default) or in base-64 format\n"
+    "\n"
+);
+
+static OptionSet *gCmdOptionSets[] =
+{
+    &gCmdOptions,
+    &gHelpOptions,
+    NULL
+};
+
+static const char *gCertFileName = NULL;
+static bool gUseBase64Decoding = false;
+enum {
+    kNumCerts = 3,
+    kCertBufSize = 1024,
+};
+
+bool Cmd_PrintServiceConfig(int argc, char *argv[])
+{
+    bool res = true;
+    WEAVE_ERROR err;
+    WeaveCertificateSet certSet;
+    uint8_t * serviceConfig = NULL;
+    uint32_t serviceConfigLen = 0;
+    TLVReader reader;
+    uint64_t serviceEndpoint;
+    TLVType serviceConfigContainer, serviceEndpointContainer, serviceDirectoryContainer;
+
+    if (argc == 1)
+    {
+        gHelpOptions.PrintBriefUsage(stderr);
+        ExitNow(res = true);
+    }
+
+    if (!ParseArgs(CMD_NAME, argc, argv, gCmdOptionSets, HandleNonOptionArgs))
+    {
+        ExitNow(res = false);
+    }
+
+    if (!ReadFileIntoMem(gCertFileName, serviceConfig, serviceConfigLen))
+    {
+        ExitNow(res = false);
+    }
+
+    if (gUseBase64Decoding)
+    {
+        uint32_t b64len = serviceConfigLen;
+        uint8_t * b64 = serviceConfig;
+        serviceConfig = (uint8_t *)malloc(serviceConfigLen);
+        if (serviceConfig == NULL)
+        {
+            fprintf(stderr, "Memory allocation error\n");
+            free(b64);
+            ExitNow(res = false);
+        }
+        serviceConfigLen = nl::Base64Decode((const char *)b64, b64len, serviceConfig);
+        free(b64);
+    }
+
+    reader.Init(serviceConfig, serviceConfigLen);
+    certSet.Init(kNumCerts, kCertBufSize);
+
+    err = reader.Next(kTLVType_Structure, ProfileTag(kWeaveProfile_ServiceProvisioning, kTag_ServiceConfig));
+    SuccessOrExit(err);
+
+    err = reader.EnterContainer(serviceConfigContainer);
+    SuccessOrExit(err);
+
+    err = reader.Next(kTLVType_Array, ContextTag(kTag_ServiceConfig_CACerts));
+    SuccessOrExit(err);
+
+    err = certSet.LoadCerts(reader, 0);
+    SuccessOrExit(err);
+
+    printf("Weave Service Config:\n\n");
+    printf("Trusted certificates:\n");
+    for (int i = 0; i < certSet.CertCount; i++)
+    {
+        printf("Certificate %d\n", i + 1);
+        PrintCert(stdout, certSet.Certs[i], NULL, 2, true);
+    }
+
+    err = reader.Next(kTLVType_Structure, ContextTag(kTag_ServiceEndPoint));
+    SuccessOrExit(err);
+
+    err = reader.EnterContainer(serviceEndpointContainer);
+    SuccessOrExit(err);
+
+    err = reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_ServiceEndPoint_Id));
+    SuccessOrExit(err);
+
+    err = reader.Get(serviceEndpoint);
+    SuccessOrExit(err);
+
+    printf("Service Endpoint ID: %016" PRIX64 "\n", serviceEndpoint);
+
+    err = reader.Next(kTLVType_Array, ContextTag(kTag_ServiceEndPoint_Addresses));
+    SuccessOrExit(err);
+
+    err = reader.EnterContainer(serviceDirectoryContainer);
+    SuccessOrExit(err);
+
+    while (err == WEAVE_NO_ERROR)
+    {
+        err = PrintServiceHostname(reader);
+    }
+    if (err == WEAVE_END_OF_TLV)
+    {
+        err = WEAVE_NO_ERROR;
+    }
+
+exit:
+    res = (err == WEAVE_NO_ERROR);
+
+    if (serviceConfig != NULL)
+    {
+        free(serviceConfig);
+    }
+    return res;
+}
+
+bool HandleNonOptionArgs(const char *progName, int argc, char *argv[])
+{
+    if (argc == 0)
+    {
+        PrintArgError("%s: Please specify the name of the certificate to be printed.\n", progName);
+        return false;
+    }
+
+    if (argc > 1)
+    {
+        PrintArgError("%s: Unexpected argument: %s\n", progName, argv[1]);
+        return false;
+    }
+
+    gCertFileName = argv[0];
+
+    return true;
+}
+
+bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
+{
+    switch (id)
+    {
+    case 'b':
+        gUseBase64Decoding = true;
+        break;
+
+    default:
+        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
+        return false;
+    }
+
+    return true;
+}
+
+WEAVE_ERROR PrintServiceHostname(TLVReader &reader)
+{
+    WEAVE_ERROR err;
+    TLVType container;
+    uint32_t len;
+    const uint8_t * strbuf = NULL;
+    uint16_t port;
+    err = reader.Next();
+    SuccessOrExit(err);
+
+    err = reader.EnterContainer(container);
+    SuccessOrExit(err);
+
+    while ((err = reader.Next()) == WEAVE_NO_ERROR)
+    {
+        uint64_t tag = reader.GetTag();
+        uint8_t tagNum;
+        if (!IsContextTag(tag))
+        {
+            continue;
+        }
+
+        tagNum = TagNumFromTag(tag);
+
+        switch (tagNum)
+        {
+            case kTag_ServiceEndPointAddress_HostName:
+                reader.GetDataPtr(strbuf);
+                len = reader.GetLength();
+                printf("Hostname: %-.*s ", (int)len, strbuf);
+                break;
+            case kTag_ServiceEndPointAddress_Port:
+                reader.Get(port);
+                printf("Port: %d ", port);
+                break;
+
+            default:
+                printf("Unknown tag num %d", tagNum);
+        }
+    }
+    printf("\n");
+    reader.ExitContainer(container);
+exit:
+    return err;
+}
diff --git a/src/tools/weave/Cmd_PrintTLV.cpp b/src/tools/weave/Cmd_PrintTLV.cpp
index d010974..d413456 100644
--- a/src/tools/weave/Cmd_PrintTLV.cpp
+++ b/src/tools/weave/Cmd_PrintTLV.cpp
@@ -48,6 +48,7 @@
 static OptionDef gCmdOptionDefs[] =
 {
     { "base64", kNoArgument, 'b' },
+    { "profile", kArgumentRequired, 'p' },
     { }
 };
 
@@ -56,6 +57,10 @@
     "\n"
     "       The file containing the TLV should be parsed as base64.\n"
     "\n"
+    "   -p, --profile <profileNumber>\n"
+    "\n"
+    "       The profile number to be used for decoding implicit tags\n"
+    "\n"
     ;
 
 static OptionSet gCmdOptions =
@@ -90,6 +95,7 @@
 
 static const char *gFileName = NULL;
 static bool gUseBase64Decoding = false;
+static uint32_t gImplicitProfileID = kProfileIdNotSpecified;
 
 bool Cmd_PrintTLV(int argc, char *argv[])
 {
@@ -98,6 +104,7 @@
     uint8_t *raw = NULL;
     int fd;
     struct stat st;
+    WEAVE_ERROR err;
     TLVReader reader;
     uint32_t len;
 
@@ -145,8 +152,12 @@
 
     printf("TLV length is %d bytes\n", len);
     reader.Init(raw, len);
-    nl::Weave::TLV::Debug::Dump(reader, _DumpWriter);
-
+    reader.ImplicitProfileId = gImplicitProfileID;
+    err = nl::Weave::TLV::Debug::Dump(reader, _DumpWriter);
+    if (err == WEAVE_ERROR_UNKNOWN_IMPLICIT_TLV_TAG)
+    {
+        printf("Data contains unknown implicit TLV encoding, for correct decode, please specify the correct implicit profile\n");
+    }
 exit:
     if (raw != NULL && raw != map)
     {
@@ -199,6 +210,13 @@
         gUseBase64Decoding = true;
         break;
 
+    case 'p':
+        if (!ParseInt(arg, gImplicitProfileID))
+        {
+            PrintArgError("s: Invalid value specified for the profile ID, \"%s\" must be an integer\n", progName, arg);
+            return false;
+        }
+        break;
     default:
         PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
         return false;
diff --git a/src/tools/weave/Makefile.am b/src/tools/weave/Makefile.am
index 2a77be5..5bdc985 100644
--- a/src/tools/weave/Makefile.am
+++ b/src/tools/weave/Makefile.am
@@ -74,6 +74,8 @@
     Cmd_GenServiceEndpointCert.cpp        \
     Cmd_MakeAccessToken.cpp               \
     Cmd_MakeServiceConfig.cpp             \
+    Cmd_PrintAccessToken.cpp              \
+    Cmd_PrintServiceConfig.cpp            \
     Cmd_PrintCert.cpp                     \
     Cmd_PrintSig.cpp                      \
     Cmd_PrintTLV.cpp                      \
diff --git a/src/tools/weave/weave-tool.cpp b/src/tools/weave/weave-tool.cpp
index b10258a..14e26a3 100644
--- a/src/tools/weave/weave-tool.cpp
+++ b/src/tools/weave/weave-tool.cpp
@@ -59,8 +59,14 @@
         "\n"
         "    make-service-config -- Make a service config object.\n"
         "\n"
+        "    make-access-token -- Make a Weave Access Token.\n"
+        "\n"
         "    validate-cert -- Validate a Weave certificate chain.\n"
         "\n"
+        "    print-access-token -- Print a Weave Access Token.\n"
+        "\n"
+        "    print-service-config -- Print a service config object\n"
+        "\n"
         "    print-cert -- Print a Weave certificate.\n"
         "\n"
         "    print-sig -- Print a Weave signature.\n"
@@ -137,6 +143,12 @@
     else if (strcasecmp(argv[1], "validate-cert") == 0 || strcasecmp(argv[1], "validatecert") == 0)
         res = Cmd_ValidateCert(argc - 1, argv + 1);
 
+    else if (strcasecmp(argv[1], "print-access-token") == 0 || strcasecmp(argv[1], "printaccesstoken") == 0)
+        res = Cmd_PrintAccessToken(argc - 1, argv + 1);
+
+    else if (strcasecmp(argv[1], "print-service-config") == 0 || strcasecmp(argv[1], "printserviceconfig") == 0)
+        res = Cmd_PrintServiceConfig(argc - 1, argv + 1);
+
     else if (strcasecmp(argv[1], "print-cert") == 0 || strcasecmp(argv[1], "printcert") == 0)
         res = Cmd_PrintCert(argc - 1, argv + 1);
 
diff --git a/src/tools/weave/weave-tool.h b/src/tools/weave/weave-tool.h
index e112966..33de037 100644
--- a/src/tools/weave/weave-tool.h
+++ b/src/tools/weave/weave-tool.h
@@ -92,6 +92,8 @@
 extern bool Cmd_MakeAccessToken(int argc, char *argv[]);
 extern bool Cmd_GenProvisioningData(int argc, char *argv[]);
 extern bool Cmd_ValidateCert(int argc, char *argv[]);
+extern bool Cmd_PrintAccessToken(int argc, char *argv[]);
+extern bool Cmd_PrintServiceConfig(int argc, char *argv[]);
 extern bool Cmd_PrintCert(int argc, char *argv[]);
 extern bool Cmd_PrintSig(int argc, char *argv[]);
 extern bool Cmd_PrintTLV(int argc, char *argv[]);