Only genenerate the random fallback MAC address once (#32694)

* Set buf.size() correctly in GetPrimaryMACAddress()

When we fall back to returning the WiFi MAC on a device that supports Thread,
the returned MAC is shorter than kPrimaryMACAddressLength.

* Only genenerate the random fallback MAC address once

This avoids changing our hostname every time we restart advertising, in
scenarios where a real physical MAC is unavailable (e.g. on iOS).
diff --git a/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.cpp b/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.cpp
index 5f4e2e1..4b9e0e5 100644
--- a/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.cpp
+++ b/examples/chef/common/clusters/wake-on-lan/WakeOnLanManager.cpp
@@ -41,7 +41,7 @@
     }
 
     char macStr[chip::DeviceLayer::ConfigurationManager::kPrimaryMACAddressLength * 2 + 1] = { 0 }; // added null char
-    if (BytesToHex(&macBuffer[0], sizeof(macBuffer), &macStr[0], sizeof(macBuffer) * 2u, chip::Encoding::HexFlags::kUppercase) !=
+    if (BytesToHex(mac.data(), mac.size(), &macStr[0], sizeof(macBuffer) * 2u, chip::Encoding::HexFlags::kUppercase) !=
         CHIP_NO_ERROR)
     {
         ChipLogProgress(Zcl, "WakeOnLanManager::getMacAddress hex conversion failed");
diff --git a/examples/tv-app/tv-common/clusters/wake-on-lan/WakeOnLanManager.cpp b/examples/tv-app/tv-common/clusters/wake-on-lan/WakeOnLanManager.cpp
index 53beede..0d4ebb6 100644
--- a/examples/tv-app/tv-common/clusters/wake-on-lan/WakeOnLanManager.cpp
+++ b/examples/tv-app/tv-common/clusters/wake-on-lan/WakeOnLanManager.cpp
@@ -39,7 +39,7 @@
     }
 
     char macStr[chip::DeviceLayer::ConfigurationManager::kPrimaryMACAddressLength * 2 + 1] = { 0 }; // added null char
-    if (BytesToHex(&macBuffer[0], sizeof(macBuffer), &macStr[0], sizeof(macBuffer) * 2u, chip::Encoding::HexFlags::kUppercase) !=
+    if (BytesToHex(mac.data(), mac.size(), &macStr[0], sizeof(macBuffer) * 2u, chip::Encoding::HexFlags::kUppercase) !=
         CHIP_NO_ERROR)
     {
         ChipLogProgress(Zcl, "WakeOnLanManager::getMacAddress hex conversion failed");
diff --git a/src/app/server/Dnssd.cpp b/src/app/server/Dnssd.cpp
index 1ec2fa0..3df7964 100644
--- a/src/app/server/Dnssd.cpp
+++ b/src/app/server/Dnssd.cpp
@@ -38,6 +38,11 @@
 #include <setup_payload/SetupPayload.h>
 #include <system/TimeSource.h>
 
+#include <algorithm>
+
+using namespace chip;
+using namespace chip::DeviceLayer;
+
 namespace chip {
 namespace app {
 namespace {
@@ -165,6 +170,21 @@
 }
 #endif
 
+void DnssdServer::GetPrimaryOrFallbackMACAddress(chip::MutableByteSpan mac)
+{
+    if (ConfigurationMgr().GetPrimaryMACAddress(mac) != CHIP_NO_ERROR)
+    {
+        // Only generate a fallback "MAC" once, so we don't keep constantly changing our host name.
+        if (std::all_of(std::begin(mFallbackMAC), std::end(mFallbackMAC), [](uint8_t v) { return v == 0; }))
+        {
+            ChipLogError(Discovery, "Failed to get primary mac address of device. Generating a random one.");
+            Crypto::DRBG_get_bytes(mFallbackMAC, sizeof(mFallbackMAC));
+        }
+        VerifyOrDie(mac.size() == sizeof(mFallbackMAC)); // kPrimaryMACAddressLength
+        memcpy(mac.data(), mFallbackMAC, sizeof(mFallbackMAC));
+    }
+}
+
 /// Set MDNS operational advertisement
 CHIP_ERROR DnssdServer::AdvertiseOperational()
 {
@@ -179,11 +199,7 @@
 
         uint8_t macBuffer[DeviceLayer::ConfigurationManager::kPrimaryMACAddressLength];
         MutableByteSpan mac(macBuffer);
-        if (chip::DeviceLayer::ConfigurationMgr().GetPrimaryMACAddress(mac) != CHIP_NO_ERROR)
-        {
-            ChipLogError(Discovery, "Failed to get primary mac address of device. Generating a random one.");
-            Crypto::DRBG_get_bytes(macBuffer, sizeof(macBuffer));
-        }
+        GetPrimaryOrFallbackMACAddress(mac);
 
         auto advertiseParameters = chip::Dnssd::OperationalAdvertisingParameters()
                                        .SetPeerId(fabricInfo.GetPeerId())
@@ -224,11 +240,7 @@
 
     uint8_t macBuffer[DeviceLayer::ConfigurationManager::kPrimaryMACAddressLength];
     MutableByteSpan mac(macBuffer);
-    if (chip::DeviceLayer::ConfigurationMgr().GetPrimaryMACAddress(mac) != CHIP_NO_ERROR)
-    {
-        ChipLogError(Discovery, "Failed to get primary mac address of device. Generating a random one.");
-        Crypto::DRBG_get_bytes(macBuffer, sizeof(macBuffer));
-    }
+    GetPrimaryOrFallbackMACAddress(mac);
     advertiseParameters.SetMac(mac);
 
     uint16_t value;
diff --git a/src/app/server/Dnssd.h b/src/app/server/Dnssd.h
index 559cac6..e669f4d 100644
--- a/src/app/server/Dnssd.h
+++ b/src/app/server/Dnssd.h
@@ -146,6 +146,11 @@
     /// Set MDNS commissionable node advertisement
     CHIP_ERROR AdvertiseCommissionableNode(chip::Dnssd::CommissioningMode mode);
 
+    // Our randomly-generated fallback "MAC address", in case we don't have a real one.
+    uint8_t mFallbackMAC[chip::DeviceLayer::ConfigurationManager::kPrimaryMACAddressLength] = { 0 };
+
+    void GetPrimaryOrFallbackMACAddress(chip::MutableByteSpan mac);
+
     //
     // Check if we have any valid operational credentials present in the fabric table and return true
     // if we do.
diff --git a/src/include/platform/ConfigurationManager.h b/src/include/platform/ConfigurationManager.h
index 4ebf2c6..c7158d2 100644
--- a/src/include/platform/ConfigurationManager.h
+++ b/src/include/platform/ConfigurationManager.h
@@ -80,17 +80,26 @@
         kMinRotatingDeviceIDUniqueIDLength = 16,
         kRotatingDeviceIDUniqueIDLength    = CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH,
 #endif
+        kEthernetMACAddressLength = 6,
+        kThreadMACAddressLength   = 8,
 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
-        kPrimaryMACAddressLength = 8,
+        kPrimaryMACAddressLength = kThreadMACAddressLength,
 #else
-        kPrimaryMACAddressLength = 6,
+        kPrimaryMACAddressLength = kEthernetMACAddressLength,
 #endif
         kMaxMACAddressLength  = 8,
         kMaxLanguageTagLength = 5 // ISO 639-1 standard language codes
     };
 
-    virtual CHIP_ERROR GetPrimaryMACAddress(MutableByteSpan buf)                           = 0;
-    virtual CHIP_ERROR GetPrimaryWiFiMACAddress(uint8_t * buf)                             = 0;
+    // Copies the primary MAC into a mutable span, which must be of size kPrimaryMACAddressLength.
+    // Upon success, the span will be reduced to the size of the MAC address being returned, which
+    // can be less than kPrimaryMACAddressLength on a device that supports Thread.
+    virtual CHIP_ERROR GetPrimaryMACAddress(MutableByteSpan buf) = 0;
+
+    // Copies the primary WiFi MAC into a buffer of size kEthernetMACAddressLength
+    virtual CHIP_ERROR GetPrimaryWiFiMACAddress(uint8_t * buf) = 0;
+
+    // Copies the primary Thread (802.15.4) MAC into a buffer of size kThreadMACAddressLength
     virtual CHIP_ERROR GetPrimary802154MACAddress(uint8_t * buf)                           = 0;
     virtual CHIP_ERROR GetSoftwareVersionString(char * buf, size_t bufSize)                = 0;
     virtual CHIP_ERROR GetSoftwareVersion(uint32_t & softwareVer)                          = 0;
diff --git a/src/include/platform/internal/GenericConfigurationManagerImpl.ipp b/src/include/platform/internal/GenericConfigurationManagerImpl.ipp
index 24c6a28..955b782 100644
--- a/src/include/platform/internal/GenericConfigurationManagerImpl.ipp
+++ b/src/include/platform/internal/GenericConfigurationManagerImpl.ipp
@@ -374,19 +374,21 @@
     if (buf.size() != ConfigurationManager::kPrimaryMACAddressLength)
         return CHIP_ERROR_INVALID_ARGUMENT;
 
-    memset(buf.data(), 0, buf.size());
+    memset(buf.data(), 0, buf.size()); // zero the whole buffer, in case the caller ignores buf.size()
 
 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
     if (chip::DeviceLayer::ThreadStackMgr().GetPrimary802154MACAddress(buf.data()) == CHIP_NO_ERROR)
     {
         ChipLogDetail(DeviceLayer, "Using Thread extended MAC for hostname.");
+        buf.reduce_size(kThreadMACAddressLength);
         return CHIP_NO_ERROR;
     }
 #endif
 
     if (chip::DeviceLayer::ConfigurationMgr().GetPrimaryWiFiMACAddress(buf.data()) == CHIP_NO_ERROR)
     {
-        ChipLogDetail(DeviceLayer, "Using wifi MAC for hostname");
+        ChipLogDetail(DeviceLayer, "Using WiFi MAC for hostname");
+        buf.reduce_size(kEthernetMACAddressLength);
         return CHIP_NO_ERROR;
     }