Add add/remove/set flag helpers for MessageHeader (#3054)

* Starting to add set/clear flag methods to the message header

* Use the new methods in the header

* Create a typesafe bitflags class and use it in MessageHeader. Mark other non-typesafe flags as deprecated

* Add sizeof check and rename Get to Has

* Add a "HasOnly" method to bitflags

* Fix usage of static assert - message is needed
diff --git a/.gitignore b/.gitignore
index 4f30ad2..94a796b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,6 @@
 
 # Doxygen outputs
 docs/html
+
+# VSCode java extensions
+.project
diff --git a/src/ble/BLEEndPoint.cpp b/src/ble/BLEEndPoint.cpp
index 52c56d7..a003ca4 100644
--- a/src/ble/BLEEndPoint.cpp
+++ b/src/ble/BLEEndPoint.cpp
@@ -36,9 +36,9 @@
 #if CONFIG_NETWORK_LAYER_BLE
 #include <core/CHIPConfig.h>
 
+#include <support/BitFlags.h>
 #include <support/CHIPFaultInjection.h>
 #include <support/CodeUtils.h>
-#include <support/FlagUtils.hpp>
 #include <support/logging/CHIPLogging.h>
 
 #include <ble/BLEEndPoint.h>
diff --git a/src/ble/BtpEngine.h b/src/ble/BtpEngine.h
index b2e8186..15051df 100644
--- a/src/ble/BtpEngine.h
+++ b/src/ble/BtpEngine.h
@@ -38,7 +38,7 @@
 #include <ble/BleConfig.h>
 
 #include <ble/BleError.h>
-#include <support/FlagUtils.hpp>
+#include <support/BitFlags.h>
 #include <system/SystemPacketBuffer.h>
 
 namespace chip {
diff --git a/src/lib/message/CHIPFabricState.h b/src/lib/message/CHIPFabricState.h
index f465028..7567157 100644
--- a/src/lib/message/CHIPFabricState.h
+++ b/src/lib/message/CHIPFabricState.h
@@ -39,9 +39,9 @@
 
 #include <core/CHIPKeyIds.h>
 #include <protocols/security/CHIPApplicationKeys.h>
+#include <support/BitFlags.h>
 #include <support/CHIPCounter.h>
 #include <support/DLLUtil.h>
-#include <support/FlagUtils.hpp>
 #include <support/PersistedCounter.h>
 
 namespace chip {
diff --git a/src/lib/message/ExchangeContext.cpp b/src/lib/message/ExchangeContext.cpp
index e7d5fe0..b4b13d0 100644
--- a/src/lib/message/ExchangeContext.cpp
+++ b/src/lib/message/ExchangeContext.cpp
@@ -39,9 +39,9 @@
 #include <message/CHIPSecurityMgr.h>
 #include <protocols/CHIPProtocols.h>
 #include <protocols/common/CommonProtocol.h>
+#include <support/BitFlags.h>
 #include <support/CHIPFaultInjection.h>
 #include <support/CodeUtils.h>
-#include <support/FlagUtils.hpp>
 #include <support/RandUtils.h>
 #include <support/logging/CHIPLogging.h>
 #include <system/SystemStats.h>
diff --git a/src/lib/support/BUILD.gn b/src/lib/support/BUILD.gn
index 159b223..cc2bce7 100644
--- a/src/lib/support/BUILD.gn
+++ b/src/lib/support/BUILD.gn
@@ -43,6 +43,7 @@
 
 support_headers = [
   "Base64.h",
+  "BitFlags.h",
   "BufBound.h",
   "CHIPCounter.h",
   "CodeUtils.h",
diff --git a/src/lib/support/BitFlags.h b/src/lib/support/BitFlags.h
new file mode 100644
index 0000000..79844cd
--- /dev/null
+++ b/src/lib/support/BitFlags.h
@@ -0,0 +1,145 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    Copyright (c) 2013-2017 Nest Labs, Inc.
+ *
+ *    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 defines functions for manipulating Boolean flags in
+ *      a bitfield.
+ *
+ */
+
+#ifndef CHIP_CHIP_SUPPORT_FLAGUTILS_HPP
+#define CHIP_CHIP_SUPPORT_FLAGUTILS_HPP
+
+#include <stdint.h>
+
+#include <utility>
+
+namespace chip {
+
+/**
+ * Stores bit flags in a type safe manner.
+ *
+ * @tparam StorageType is the underlying storage type (like uint16_t, uint32_t etc.)
+ * @tparam FlagsEnum is the typesafe flags setting
+ */
+template <typename StorageType, typename FlagsEnum>
+class BitFlags
+{
+public:
+    static_assert(sizeof(StorageType) >= sizeof(FlagsEnum), "All flags should fit in the storage type");
+
+    BitFlags() {}
+    BitFlags(const BitFlags &) = default;
+    BitFlags & operator=(const BitFlags &) = default;
+
+    BitFlags & Set(FlagsEnum v)
+    {
+        mValue = static_cast<StorageType>(mValue | static_cast<StorageType>(v));
+        return *this;
+    }
+
+    BitFlags & Clear(FlagsEnum v)
+    {
+        mValue &= static_cast<StorageType>(~static_cast<StorageType>(v));
+        return *this;
+    }
+
+    BitFlags & Set(FlagsEnum v, bool isSet) { return isSet ? Set(v) : Clear(v); }
+
+    bool Has(FlagsEnum v) const { return (mValue & static_cast<StorageType>(v)) != 0; }
+
+    BitFlags & Set(const BitFlags & other)
+    {
+        mValue |= other.mValue;
+        return *this;
+    }
+
+    StorageType Raw() const { return mValue; }
+    BitFlags & SetRaw(StorageType value)
+    {
+        mValue = value;
+        return *this;
+    }
+
+    /** Check that no flags outside the arguments are set.*/
+    template <typename... Args>
+    bool HasOnly(Args &&... args) const
+    {
+        return IsZeroAfterClearing(mValue, std::forward<Args>(args)...);
+    }
+
+private:
+    StorageType mValue = 0;
+
+    template <typename... Args>
+    static bool IsZeroAfterClearing(StorageType value, FlagsEnum flagToClear, Args &&... args)
+    {
+        value &= static_cast<StorageType>(~static_cast<StorageType>(flagToClear));
+        return IsZeroAfterClearing(value, std::forward<Args>(args)...);
+    }
+
+    static bool IsZeroAfterClearing(StorageType value) { return value == 0; }
+};
+
+/**
+ * @deprecated Use typesafe BitFlags class instead.
+ */
+template <typename FlagsT, typename FlagT>
+inline bool GetFlag(const FlagsT & inFlags, const FlagT inFlag)
+{
+    return (inFlags & static_cast<FlagsT>(inFlag)) != 0;
+}
+
+/**
+ * @deprecated Use typesafe BitFlags class instead.
+ */
+template <typename FlagsT, typename FlagT>
+inline void ClearFlag(FlagsT & inFlags, const FlagT inFlag)
+{
+    inFlags &= static_cast<FlagsT>(~static_cast<FlagsT>(inFlag));
+}
+
+/**
+ * @deprecated Use typesafe BitFlags class instead.
+ */
+template <typename FlagsT, typename FlagT>
+inline void SetFlag(FlagsT & inFlags, const FlagT inFlag)
+{
+    inFlags = static_cast<FlagsT>(inFlags | static_cast<FlagsT>(inFlag));
+}
+
+/**
+ * @deprecated Use typesafe BitFlags class instead.
+ */
+template <typename FlagsT, typename FlagT>
+inline void SetFlag(FlagsT & inFlags, const FlagT inFlag, const bool inValue)
+{
+    if (inValue)
+    {
+        SetFlag(inFlags, inFlag);
+    }
+    else
+    {
+        ClearFlag(inFlags, inFlag);
+    }
+}
+
+} // namespace chip
+
+#endif // CHIP_CHIP_SUPPORT_FLAGUTILS_HPP
diff --git a/src/lib/support/FlagUtils.hpp b/src/lib/support/FlagUtils.hpp
deleted file mode 100644
index 0528e9c..0000000
--- a/src/lib/support/FlagUtils.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- *
- *    Copyright (c) 2020 Project CHIP Authors
- *    Copyright (c) 2013-2017 Nest Labs, Inc.
- *
- *    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 defines functions for manipulating Boolean flags in
- *      a bitfield.
- *
- */
-
-#ifndef CHIP_CHIP_SUPPORT_FLAGUTILS_HPP
-#define CHIP_CHIP_SUPPORT_FLAGUTILS_HPP
-
-#include <stdint.h>
-
-namespace chip {
-
-template <typename FlagsT, typename FlagT>
-inline bool GetFlag(const FlagsT & inFlags, const FlagT inFlag)
-{
-    return (inFlags & static_cast<FlagsT>(inFlag)) != 0;
-}
-
-template <typename FlagsT, typename FlagT>
-inline void ClearFlag(FlagsT & inFlags, const FlagT inFlag)
-{
-    inFlags &= static_cast<FlagsT>(~static_cast<FlagsT>(inFlag));
-}
-
-template <typename FlagsT, typename FlagT>
-inline void SetFlag(FlagsT & inFlags, const FlagT inFlag)
-{
-    inFlags = static_cast<FlagsT>(inFlags | static_cast<FlagsT>(inFlag));
-}
-
-template <typename FlagsT, typename FlagT>
-inline void SetFlag(FlagsT & inFlags, const FlagT inFlag, const bool inValue)
-{
-    if (inValue)
-    {
-        SetFlag(inFlags, inFlag);
-    }
-    else
-    {
-        ClearFlag(inFlags, inFlag);
-    }
-}
-
-} // namespace chip
-
-#endif // CHIP_CHIP_SUPPORT_FLAGUTILS_HPP
diff --git a/src/platform/Darwin/ConnectivityManagerImpl.h b/src/platform/Darwin/ConnectivityManagerImpl.h
index 41c10f1..20fd1ea 100644
--- a/src/platform/Darwin/ConnectivityManagerImpl.h
+++ b/src/platform/Darwin/ConnectivityManagerImpl.h
@@ -32,7 +32,6 @@
 #include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
 #endif
 #include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
-#include <support/FlagUtils.hpp>
 
 namespace chip {
 namespace Inet {
diff --git a/src/platform/EFR32/ConnectivityManagerImpl.h b/src/platform/EFR32/ConnectivityManagerImpl.h
index 1c24076..55e1c53 100644
--- a/src/platform/EFR32/ConnectivityManagerImpl.h
+++ b/src/platform/EFR32/ConnectivityManagerImpl.h
@@ -32,7 +32,6 @@
 #include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
 #endif
 #include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
-#include <support/FlagUtils.hpp>
 
 namespace Inet {
 class IPAddress;
diff --git a/src/platform/ESP32/ConnectivityManagerImpl.h b/src/platform/ESP32/ConnectivityManagerImpl.h
index f2b2705..0f627e0 100644
--- a/src/platform/ESP32/ConnectivityManagerImpl.h
+++ b/src/platform/ESP32/ConnectivityManagerImpl.h
@@ -28,7 +28,6 @@
 #include <platform/internal/GenericConnectivityManagerImpl_NoBLE.h>
 #endif
 #include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
-#include <support/FlagUtils.hpp>
 
 #include "esp_event.h"
 
diff --git a/src/platform/K32W/ConnectivityManagerImpl.h b/src/platform/K32W/ConnectivityManagerImpl.h
index ad7a8b8..5a11b75 100644
--- a/src/platform/K32W/ConnectivityManagerImpl.h
+++ b/src/platform/K32W/ConnectivityManagerImpl.h
@@ -33,7 +33,6 @@
 #include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
 #endif
 #include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
-#include <support/FlagUtils.hpp>
 
 namespace chip {
 namespace DeviceLayer {
diff --git a/src/platform/Linux/ConnectivityManagerImpl.h b/src/platform/Linux/ConnectivityManagerImpl.h
index 6085696..432ec86 100644
--- a/src/platform/Linux/ConnectivityManagerImpl.h
+++ b/src/platform/Linux/ConnectivityManagerImpl.h
@@ -36,7 +36,6 @@
 #else
 #include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
 #endif
-#include <support/FlagUtils.hpp>
 
 #if CHIP_DEVICE_CONFIG_ENABLE_WPA
 #include <platform/Linux/dbus/wpa/DBusWpa.h>
diff --git a/src/platform/nRF5/ConnectivityManagerImpl.h b/src/platform/nRF5/ConnectivityManagerImpl.h
index d5ce8e1..1b808a5 100644
--- a/src/platform/nRF5/ConnectivityManagerImpl.h
+++ b/src/platform/nRF5/ConnectivityManagerImpl.h
@@ -32,7 +32,6 @@
 #include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
 #endif
 #include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
-#include <support/FlagUtils.hpp>
 
 namespace chip {
 namespace Inet {
diff --git a/src/platform/nrfconnect/ConnectivityManagerImpl.h b/src/platform/nrfconnect/ConnectivityManagerImpl.h
index 4165fe9..fda70ac 100644
--- a/src/platform/nrfconnect/ConnectivityManagerImpl.h
+++ b/src/platform/nrfconnect/ConnectivityManagerImpl.h
@@ -31,7 +31,6 @@
 #include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
 #endif
 #include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
-#include <support/FlagUtils.hpp>
 
 #include <support/logging/CHIPLogging.h>
 
diff --git a/src/platform/qpg6100/ConnectivityManagerImpl.h b/src/platform/qpg6100/ConnectivityManagerImpl.h
index 3803430..661cb62 100644
--- a/src/platform/qpg6100/ConnectivityManagerImpl.h
+++ b/src/platform/qpg6100/ConnectivityManagerImpl.h
@@ -31,7 +31,6 @@
 #include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
 #endif
 #include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
-#include <support/FlagUtils.hpp>
 
 namespace chip {
 namespace Inet {
diff --git a/src/transport/RendezvousSession.cpp b/src/transport/RendezvousSession.cpp
index 469bff9..ea2ae84 100644
--- a/src/transport/RendezvousSession.cpp
+++ b/src/transport/RendezvousSession.cpp
@@ -123,7 +123,7 @@
     SuccessOrExit(err);
 
     msgBuf->ConsumeHead(headerSize);
-    err = mTransport->SendMessage(header, Header::Flags::None(), Transport::PeerAddress::BLE(), msgBuf);
+    err = mTransport->SendMessage(header, Header::Flags(), Transport::PeerAddress::BLE(), msgBuf);
     SuccessOrExit(err);
 
 exit:
diff --git a/src/transport/raw/MessageHeader.cpp b/src/transport/raw/MessageHeader.cpp
index d884130..056071e 100644
--- a/src/transport/raw/MessageHeader.cpp
+++ b/src/transport/raw/MessageHeader.cpp
@@ -149,11 +149,11 @@
     VerifyOrExit(version == kHeaderVersion, err = CHIP_ERROR_VERSION_MISMATCH);
 
     mEncryptionType = static_cast<Header::EncryptionType>((header & kEncryptionTypeMask) >> kEncryptionTypeShift);
-    mFlags.value    = header & Header::Flags::kMask;
+    mFlags.SetRaw(header & Header::kFlagsMask);
 
     mMessageId = LittleEndian::Read32(p);
 
-    if (mFlags.value & Header::Flags::kSourceNodeIdPresent)
+    if (mFlags.Has(Header::FlagValues::kSourceNodeIdPresent))
     {
         static_assert(kNodeIdSizeBytes == 8, "Read64 might read more bytes than we have in the buffer");
         VerifyOrExit(size >= static_cast<size_t>(p - data) + kNodeIdSizeBytes, err = CHIP_ERROR_INVALID_ARGUMENT);
@@ -164,7 +164,7 @@
         mSourceNodeId.ClearValue();
     }
 
-    if (mFlags.value & Header::Flags::kDestinationNodeIdPresent)
+    if (mFlags.Has(Header::FlagValues::kDestinationNodeIdPresent))
     {
         VerifyOrExit(size >= static_cast<size_t>(p - data) + kNodeIdSizeBytes, err = CHIP_ERROR_INVALID_ARGUMENT);
         mDestinationNodeId.SetValue(LittleEndian::Read64(p));
@@ -197,7 +197,7 @@
     mMessageType    = Read8(p);
     mExchangeID     = LittleEndian::Read16(p);
 
-    if (flags.value & Header::Flags::kVendorIdPresent)
+    if (flags.Has(Header::FlagValues::kVendorIdPresent))
     {
         VerifyOrExit(size >= static_cast<size_t>(p - data) + kVendorIdSizeBytes, err = CHIP_ERROR_INVALID_ARGUMENT);
         mVendorId.SetValue(LittleEndian::Read16(p));
@@ -226,19 +226,16 @@
 
     VerifyOrExit(size >= EncodeSizeBytes(), err = CHIP_ERROR_INVALID_ARGUMENT);
 
-    // Payload flags are restricted.
-    VerifyOrExit((payloadFlags.value & Header::Flags::kValidPayloadFlags) == payloadFlags.value, err = CHIP_ERROR_INVALID_ARGUMENT);
-
-    header |= mFlags.value;
-    header |= payloadFlags.value;
-
-    if (mSourceNodeId.HasValue())
     {
-        header |= Header::Flags::kSourceNodeIdPresent;
-    }
-    if (mDestinationNodeId.HasValue())
-    {
-        header |= Header::Flags::kDestinationNodeIdPresent;
+        // Payload flags are restricted.
+        VerifyOrExit(payloadFlags.HasOnly(Header::FlagValues::kVendorIdPresent), err = CHIP_ERROR_INVALID_ARGUMENT);
+
+        Header::Flags encodeFlags = mFlags;
+        encodeFlags.Set(payloadFlags)
+            .Set(Header::FlagValues::kSourceNodeIdPresent, mSourceNodeId.HasValue())
+            .Set(Header::FlagValues::kDestinationNodeIdPresent, mDestinationNodeId.HasValue());
+
+        header = header | encodeFlags.Raw();
     }
 
     header |= (static_cast<uint16_t>(static_cast<uint16_t>(mEncryptionType) << kEncryptionTypeShift) & kEncryptionTypeMask);
@@ -290,12 +287,7 @@
 
 Header::Flags PayloadHeader::GetEncodePacketFlags() const
 {
-    Header::Flags result;
-    if (mVendorId.HasValue())
-    {
-        result.value |= Header::Flags::kVendorIdPresent;
-    }
-    return result;
+    return Header::Flags().Set(Header::FlagValues::kVendorIdPresent, mVendorId.HasValue());
 }
 
 CHIP_ERROR MessageAuthenticationCode::Decode(const PacketHeader & packetHeader, const uint8_t * const data, size_t size,
diff --git a/src/transport/raw/MessageHeader.h b/src/transport/raw/MessageHeader.h
index aee247c..77c8976 100644
--- a/src/transport/raw/MessageHeader.h
+++ b/src/transport/raw/MessageHeader.h
@@ -29,6 +29,7 @@
 
 #include <core/CHIPError.h>
 #include <core/Optional.h>
+#include <support/BitFlags.h>
 
 namespace chip {
 
@@ -49,34 +50,30 @@
     kAESCCMTagLen16 = 2,
 };
 
-struct Flags
+enum class FlagValues : uint16_t
 {
-    uint16_t value = 0;
-
-    static constexpr Flags None() { return Flags(); }
-
     /// Header flag specifying that a destination node id is included in the header.
-    static constexpr uint16_t kDestinationNodeIdPresent = 0x0100;
+    kDestinationNodeIdPresent = 0x0100,
 
     /// Header flag specifying that a source node id is included in the header.
-    static constexpr uint16_t kSourceNodeIdPresent = 0x0200;
+    kSourceNodeIdPresent = 0x0200,
 
     /// Header flag specifying that a source vendor id is included in the header.
-    static constexpr uint16_t kVendorIdPresent = 0x0400;
+    kVendorIdPresent = 0x0400,
 
     /// Header flag specifying that it is a control message for secure session.
-    static constexpr uint16_t kSecureSessionControlMessage = 0x0800;
+    kSecureSessionControlMessage = 0x0800,
 
-    // Header is a 16-bit value of the form
-    //  |  4 bit  | 4 bit |  4 bit  |  4 bit   |
-    //  +---------+-------+---------+----------|
-    //  | version | Flags | encType | reserved |
-    static constexpr uint16_t kMask = 0x0F00;
-
-    // Flags of what is in a payload are restricted.
-    static constexpr uint16_t kValidPayloadFlags = kVendorIdPresent;
 };
 
+using Flags = BitFlags<uint16_t, FlagValues>;
+
+// Header is a 16-bit value of the form
+//  |  4 bit  | 4 bit |  4 bit  |  4 bit   |
+//  +---------+-------+---------+----------|
+//  | version | Flags | encType | reserved |
+static constexpr uint16_t kFlagsMask = 0x0F00;
+
 } // namespace Header
 
 /**
@@ -115,51 +112,38 @@
     /** Get the length of encrypted payload. */
     uint16_t GetPayloadLength() const { return mPayloadLength; }
 
+    Header::Flags & GetFlags() { return mFlags; }
     const Header::Flags & GetFlags() const { return mFlags; }
 
     /** Check if it's a secure session control message. */
-    bool IsSecureSessionControlMsg() const { return (mFlags.value & Header::Flags::kSecureSessionControlMessage) != 0; }
+    bool IsSecureSessionControlMsg() const { return mFlags.Has(Header::FlagValues::kSecureSessionControlMessage); }
 
     Header::EncryptionType GetEncryptionType() const { return mEncryptionType; }
 
     PacketHeader & SetSecureSessionControlMsg(bool value)
     {
-        if (value)
-        {
-            mFlags.value |= Header::Flags::kSecureSessionControlMessage;
-        }
-        else
-        {
-            mFlags.value = static_cast<uint16_t>(mFlags.value & ~Header::Flags::kSecureSessionControlMessage);
-        }
+        mFlags.Set(Header::FlagValues::kSecureSessionControlMessage, value);
         return *this;
     }
 
     PacketHeader & SetSourceNodeId(NodeId id)
     {
         mSourceNodeId.SetValue(id);
-        mFlags.value |= Header::Flags::kSourceNodeIdPresent;
+        mFlags.Set(Header::FlagValues::kSourceNodeIdPresent);
         return *this;
     }
 
     PacketHeader & SetSourceNodeId(Optional<NodeId> id)
     {
         mSourceNodeId = id;
-        if (id.HasValue())
-        {
-            mFlags.value |= Header::Flags::kSourceNodeIdPresent;
-        }
-        else
-        {
-            mFlags.value = static_cast<uint16_t>(mFlags.value & ~Header::Flags::kSourceNodeIdPresent);
-        }
+        mFlags.Set(Header::FlagValues::kSourceNodeIdPresent, id.HasValue());
         return *this;
     }
 
     PacketHeader & ClearSourceNodeId()
     {
-        mFlags.value = static_cast<uint16_t>(mFlags.value & ~Header::Flags::kSourceNodeIdPresent);
         mSourceNodeId.ClearValue();
+        mFlags.Clear(Header::FlagValues::kSourceNodeIdPresent);
         return *this;
     }
 
@@ -172,29 +156,22 @@
 
     PacketHeader & SetDestinationNodeId(NodeId id)
     {
-        mFlags.value |= Header::Flags::kDestinationNodeIdPresent;
         mDestinationNodeId.SetValue(id);
+        mFlags.Set(Header::FlagValues::kDestinationNodeIdPresent);
         return *this;
     }
 
     PacketHeader & SetDestinationNodeId(Optional<NodeId> id)
     {
         mDestinationNodeId = id;
-        if (id.HasValue())
-        {
-            mFlags.value |= Header::Flags::kDestinationNodeIdPresent;
-        }
-        else
-        {
-            mFlags.value = static_cast<uint16_t>(mFlags.value & ~Header::Flags::kDestinationNodeIdPresent);
-        }
+        mFlags.Set(Header::FlagValues::kDestinationNodeIdPresent, id.HasValue());
         return *this;
     }
 
     PacketHeader & ClearDestinationNodeId()
     {
-        mFlags.value = static_cast<uint16_t>(mFlags.value & ~Header::Flags::kDestinationNodeIdPresent);
         mDestinationNodeId.ClearValue();
+        mFlags.Clear(Header::FlagValues::kDestinationNodeIdPresent);
         return *this;
     }
 
diff --git a/src/transport/raw/tests/TestMessageHeader.cpp b/src/transport/raw/tests/TestMessageHeader.cpp
index 3965733..54fc95b 100644
--- a/src/transport/raw/tests/TestMessageHeader.cpp
+++ b/src/transport/raw/tests/TestMessageHeader.cpp
@@ -64,7 +64,7 @@
     uint16_t decodeLen;
 
     header.SetMessageId(123).SetPayloadLength(16);
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags()) == CHIP_NO_ERROR);
 
     // change it to verify decoding
     header.SetMessageId(222).SetSourceNodeId(1).SetDestinationNodeId(2);
@@ -75,7 +75,7 @@
     NL_TEST_ASSERT(inSuite, !header.GetDestinationNodeId().HasValue());
 
     header.SetSourceNodeId(55);
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags()) == CHIP_NO_ERROR);
 
     // change it to verify decoding
     header.SetMessageId(222).SetSourceNodeId(1).SetDestinationNodeId(2);
@@ -87,7 +87,7 @@
     NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional<uint64_t>::Value(55));
 
     header.ClearSourceNodeId().SetDestinationNodeId(11);
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags()) == CHIP_NO_ERROR);
 
     // change it to verify decoding
     header.SetMessageId(222).SetSourceNodeId(1).SetDestinationNodeId(2);
@@ -98,7 +98,7 @@
     NL_TEST_ASSERT(inSuite, !header.GetSourceNodeId().HasValue());
 
     header.SetMessageId(234).SetSourceNodeId(77).SetDestinationNodeId(88);
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags()) == CHIP_NO_ERROR);
 
     // change it to verify decoding
     header.SetMessageId(222).SetSourceNodeId(1).SetDestinationNodeId(2);
@@ -109,7 +109,7 @@
     NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional<uint64_t>::Value(77));
 
     header.SetMessageId(234).SetSourceNodeId(77).SetDestinationNodeId(88).SetSecureSessionControlMsg(true);
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags()) == CHIP_NO_ERROR);
 
     // change it to verify decoding
     header.SetMessageId(222).SetSourceNodeId(1).SetDestinationNodeId(2);
@@ -120,7 +120,7 @@
     NL_TEST_ASSERT(inSuite, header.IsSecureSessionControlMsg());
 
     header.SetMessageId(234).SetSourceNodeId(77).SetDestinationNodeId(88).SetEncryptionKeyID(2);
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags()) == CHIP_NO_ERROR);
 
     // change it to verify decoding
     header.SetMessageId(222).SetSourceNodeId(1).SetDestinationNodeId(2);
@@ -131,7 +131,7 @@
     NL_TEST_ASSERT(inSuite, header.GetEncryptionKeyID() == 2);
 
     header.SetMessageId(234).SetSourceNodeId(77).SetDestinationNodeId(88);
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen, Header::Flags()) == CHIP_NO_ERROR);
 
     // change it to verify decoding
     header.SetMessageId(222).SetSourceNodeId(1).SetDestinationNodeId(2);
@@ -155,7 +155,7 @@
     NL_TEST_ASSERT(inSuite, header.Encode(buffer, sizeof(buffer), &encodeLen) == CHIP_NO_ERROR);
 
     header.SetMessageType(221).SetExchangeID(3322).SetProtocolID(4567);
-    NL_TEST_ASSERT(inSuite, header.Decode(Header::Flags::None(), buffer, sizeof(buffer), &decodeLen) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Decode(Header::Flags(), buffer, sizeof(buffer), &decodeLen) == CHIP_NO_ERROR);
     NL_TEST_ASSERT(inSuite, encodeLen == decodeLen);
     NL_TEST_ASSERT(inSuite, header.GetMessageType() == 112);
     NL_TEST_ASSERT(inSuite, header.GetExchangeID() == 2233);
@@ -193,7 +193,7 @@
 
     for (size_t shortLen = 0; shortLen < 10; shortLen++)
     {
-        NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen, Header::Flags::None()) != CHIP_NO_ERROR);
+        NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen, Header::Flags()) != CHIP_NO_ERROR);
         NL_TEST_ASSERT(inSuite, header.Decode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR);
     }
 
@@ -201,7 +201,7 @@
     // default-constructed PacketHeader.
     static const size_t minLen = 10;
     uint16_t encoded_len;
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen, &encoded_len, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen, &encoded_len, Header::Flags()) == CHIP_NO_ERROR);
     NL_TEST_ASSERT(inSuite, encoded_len == minLen);
     // Verify that decoding at any smaller length fails.
     for (size_t shortLen = 0; shortLen < encoded_len; shortLen++)
@@ -216,9 +216,9 @@
     header.SetSourceNodeId(1);
     for (size_t shortLen = minLen; shortLen < minLen + 8; shortLen++)
     {
-        NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen, Header::Flags::None()) != CHIP_NO_ERROR);
+        NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen, Header::Flags()) != CHIP_NO_ERROR);
     }
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen + 8, &encoded_len, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen + 8, &encoded_len, Header::Flags()) == CHIP_NO_ERROR);
     NL_TEST_ASSERT(inSuite, encoded_len == minLen + 8);
     for (size_t shortLen = 0; shortLen < encoded_len; shortLen++)
     {
@@ -231,9 +231,9 @@
     header.SetDestinationNodeId(1);
     for (size_t shortLen = minLen; shortLen < minLen + 16; shortLen++)
     {
-        NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen, Header::Flags::None()) != CHIP_NO_ERROR);
+        NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen, Header::Flags()) != CHIP_NO_ERROR);
     }
-    NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen + 16, &encoded_len, Header::Flags::None()) == CHIP_NO_ERROR);
+    NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen + 16, &encoded_len, Header::Flags()) == CHIP_NO_ERROR);
     NL_TEST_ASSERT(inSuite, encoded_len == minLen + 16);
     for (size_t shortLen = 0; shortLen < encoded_len; shortLen++)
     {
@@ -252,7 +252,7 @@
     for (size_t shortLen = 0; shortLen < 6; shortLen++)
     {
         NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR);
-        NL_TEST_ASSERT(inSuite, header.Decode(Header::Flags::None(), buffer, shortLen, &unusedLen) != CHIP_NO_ERROR);
+        NL_TEST_ASSERT(inSuite, header.Decode(Header::Flags(), buffer, shortLen, &unusedLen) != CHIP_NO_ERROR);
     }
 }
 
diff --git a/src/transport/raw/tests/TestTCP.cpp b/src/transport/raw/tests/TestTCP.cpp
index c9f44f9..b67eef1 100644
--- a/src/transport/raw/tests/TestTCP.cpp
+++ b/src/transport/raw/tests/TestTCP.cpp
@@ -126,7 +126,7 @@
     header.SetSourceNodeId(kSourceNodeId).SetDestinationNodeId(kDestinationNodeId).SetMessageId(kMessageId);
 
     // Should be able to send a message to itself by just calling send.
-    err = tcp.SendMessage(header, Header::Flags::None(), Transport::PeerAddress::TCP(addr), buffer);
+    err = tcp.SendMessage(header, Header::Flags(), Transport::PeerAddress::TCP(addr), buffer);
     if (err == System::MapErrorPOSIX(EADDRNOTAVAIL))
     {
         // TODO(#2698): the underlying system does not support IPV6. This early return
diff --git a/src/transport/raw/tests/TestUDP.cpp b/src/transport/raw/tests/TestUDP.cpp
index d0347f0..fcb76ba 100644
--- a/src/transport/raw/tests/TestUDP.cpp
+++ b/src/transport/raw/tests/TestUDP.cpp
@@ -123,7 +123,7 @@
     header.SetSourceNodeId(kSourceNodeId).SetDestinationNodeId(kDestinationNodeId).SetMessageId(kMessageId);
 
     // Should be able to send a message to itself by just calling send.
-    err = udp.SendMessage(header, Header::Flags::None(), Transport::PeerAddress::UDP(addr), buffer);
+    err = udp.SendMessage(header, Header::Flags(), Transport::PeerAddress::UDP(addr), buffer);
     if (err == System::MapErrorPOSIX(EADDRNOTAVAIL))
     {
         // TODO(#2698): the underlying system does not support IPV6. This early return
diff --git a/src/transport/tests/TestSecureSession.cpp b/src/transport/tests/TestSecureSession.cpp
index 3853422..9f11820 100644
--- a/src/transport/tests/TestSecureSession.cpp
+++ b/src/transport/tests/TestSecureSession.cpp
@@ -84,7 +84,7 @@
 
     // Test uninitialized channel
     NL_TEST_ASSERT(inSuite,
-                   channel.Encrypt(plain_text, sizeof(plain_text), output, packetHeader, Header::Flags::None(), mac) ==
+                   channel.Encrypt(plain_text, sizeof(plain_text), output, packetHeader, Header::Flags(), mac) ==
                        CHIP_ERROR_INVALID_USE_OF_SESSION_KEY);
 
     const char * info = "Test Info";
@@ -95,17 +95,16 @@
 
     // Test initialized channel, but invalid arguments
     NL_TEST_ASSERT(inSuite,
-                   channel.Encrypt(nullptr, 0, nullptr, packetHeader, Header::Flags::None(), mac) == CHIP_ERROR_INVALID_ARGUMENT);
-    NL_TEST_ASSERT(
-        inSuite, channel.Encrypt(plain_text, 0, nullptr, packetHeader, Header::Flags::None(), mac) == CHIP_ERROR_INVALID_ARGUMENT);
+                   channel.Encrypt(nullptr, 0, nullptr, packetHeader, Header::Flags(), mac) == CHIP_ERROR_INVALID_ARGUMENT);
     NL_TEST_ASSERT(inSuite,
-                   channel.Encrypt(plain_text, sizeof(plain_text), nullptr, packetHeader, Header::Flags::None(), mac) ==
+                   channel.Encrypt(plain_text, 0, nullptr, packetHeader, Header::Flags(), mac) == CHIP_ERROR_INVALID_ARGUMENT);
+    NL_TEST_ASSERT(inSuite,
+                   channel.Encrypt(plain_text, sizeof(plain_text), nullptr, packetHeader, Header::Flags(), mac) ==
                        CHIP_ERROR_INVALID_ARGUMENT);
 
     // Valid arguments
     NL_TEST_ASSERT(inSuite,
-                   channel.Encrypt(plain_text, sizeof(plain_text), output, packetHeader, Header::Flags::None(), mac) ==
-                       CHIP_NO_ERROR);
+                   channel.Encrypt(plain_text, sizeof(plain_text), output, packetHeader, Header::Flags(), mac) == CHIP_NO_ERROR);
 }
 
 void SecureChannelDecryptTest(nlTestSuite * inSuite, void * inContext)
@@ -129,14 +128,13 @@
                    channel.Init(keypair, keypair2.Pubkey(), (const uint8_t *) salt, sizeof(salt), (const uint8_t *) info,
                                 sizeof(info)) == CHIP_NO_ERROR);
     NL_TEST_ASSERT(inSuite,
-                   channel.Encrypt(plain_text, sizeof(plain_text), encrypted, packetHeader, Header::Flags::None(), mac) ==
-                       CHIP_NO_ERROR);
+                   channel.Encrypt(plain_text, sizeof(plain_text), encrypted, packetHeader, Header::Flags(), mac) == CHIP_NO_ERROR);
 
     SecureSession channel2;
     uint8_t output[128];
     // Uninitialized channel
     NL_TEST_ASSERT(inSuite,
-                   channel2.Decrypt(encrypted, sizeof(plain_text), output, packetHeader, Header::Flags::None(), mac) ==
+                   channel2.Decrypt(encrypted, sizeof(plain_text), output, packetHeader, Header::Flags(), mac) ==
                        CHIP_ERROR_INVALID_USE_OF_SESSION_KEY);
     NL_TEST_ASSERT(inSuite,
                    channel2.Init(keypair2, keypair.Pubkey(), (const uint8_t *) salt, sizeof(salt), (const uint8_t *) info,
@@ -144,17 +142,16 @@
 
     // Channel initialized, but invalid arguments to decrypt
     NL_TEST_ASSERT(inSuite,
-                   channel2.Decrypt(nullptr, 0, nullptr, packetHeader, Header::Flags::None(), mac) == CHIP_ERROR_INVALID_ARGUMENT);
-    NL_TEST_ASSERT(
-        inSuite, channel2.Decrypt(encrypted, 0, nullptr, packetHeader, Header::Flags::None(), mac) == CHIP_ERROR_INVALID_ARGUMENT);
+                   channel2.Decrypt(nullptr, 0, nullptr, packetHeader, Header::Flags(), mac) == CHIP_ERROR_INVALID_ARGUMENT);
     NL_TEST_ASSERT(inSuite,
-                   channel2.Decrypt(encrypted, sizeof(encrypted), nullptr, packetHeader, Header::Flags::None(), mac) ==
+                   channel2.Decrypt(encrypted, 0, nullptr, packetHeader, Header::Flags(), mac) == CHIP_ERROR_INVALID_ARGUMENT);
+    NL_TEST_ASSERT(inSuite,
+                   channel2.Decrypt(encrypted, sizeof(encrypted), nullptr, packetHeader, Header::Flags(), mac) ==
                        CHIP_ERROR_INVALID_ARGUMENT);
 
     // Valid arguments
     NL_TEST_ASSERT(inSuite,
-                   channel2.Decrypt(encrypted, sizeof(plain_text), output, packetHeader, Header::Flags::None(), mac) ==
-                       CHIP_NO_ERROR);
+                   channel2.Decrypt(encrypted, sizeof(plain_text), output, packetHeader, Header::Flags(), mac) == CHIP_NO_ERROR);
 
     NL_TEST_ASSERT(inSuite, memcmp(plain_text, output, sizeof(plain_text)) == 0);
 }