|  | /* | 
|  | * | 
|  | *    Copyright (c) 2020 Project CHIP Authors | 
|  | *    Copyright (c) 2018 Nest Labs, Inc. | 
|  | *    All rights reserved. | 
|  | * | 
|  | *    Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | *    you may not use this file except in compliance with the License. | 
|  | *    You may obtain a copy of the License at | 
|  | * | 
|  | *        http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | *    Unless required by applicable law or agreed to in writing, software | 
|  | *    distributed under the License is distributed on an "AS IS" BASIS, | 
|  | *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | *    See the License for the specific language governing permissions and | 
|  | *    limitations under the License. | 
|  | */ | 
|  |  | 
|  | /** | 
|  | *    @file | 
|  | *          Provides the implementation of the Device Layer ConfigurationManager object | 
|  | *          for Linux platforms. | 
|  | */ | 
|  |  | 
|  | #include <app-common/zap-generated/cluster-objects.h> | 
|  | #include <ifaddrs.h> | 
|  | #include <lib/core/CHIPVendorIdentifiers.hpp> | 
|  | #include <lib/support/CodeUtils.h> | 
|  | #include <lib/support/logging/CHIPLogging.h> | 
|  | #include <netpacket/packet.h> | 
|  | #include <platform/CHIPDeviceConfig.h> | 
|  | #include <platform/ConfigurationManager.h> | 
|  | #include <platform/DiagnosticDataProvider.h> | 
|  | #include <platform/Linux/PosixConfig.h> | 
|  | #include <platform/internal/GenericConfigurationManagerImpl.ipp> | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | namespace chip { | 
|  | namespace DeviceLayer { | 
|  |  | 
|  | using namespace ::chip::DeviceLayer::Internal; | 
|  |  | 
|  | ConfigurationManagerImpl & ConfigurationManagerImpl::GetDefaultInstance() | 
|  | { | 
|  | static ConfigurationManagerImpl sInstance; | 
|  | return sInstance; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::Init() | 
|  | { | 
|  | CHIP_ERROR err; | 
|  | uint32_t rebootCount; | 
|  |  | 
|  | // Force initialization of NVS namespaces if they doesn't already exist. | 
|  | err = PosixConfig::EnsureNamespace(PosixConfig::kConfigNamespace_ChipFactory); | 
|  | SuccessOrExit(err); | 
|  | err = PosixConfig::EnsureNamespace(PosixConfig::kConfigNamespace_ChipConfig); | 
|  | SuccessOrExit(err); | 
|  | err = PosixConfig::EnsureNamespace(PosixConfig::kConfigNamespace_ChipCounters); | 
|  | SuccessOrExit(err); | 
|  |  | 
|  | // Initialize the generic implementation base class. | 
|  | err = Internal::GenericConfigurationManagerImpl<PosixConfig>::Init(); | 
|  | SuccessOrExit(err); | 
|  |  | 
|  | if (!PosixConfig::ConfigValueExists(PosixConfig::kConfigKey_VendorId)) | 
|  | { | 
|  | err = StoreVendorId(CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  |  | 
|  | if (!PosixConfig::ConfigValueExists(PosixConfig::kConfigKey_ProductId)) | 
|  | { | 
|  | err = StoreProductId(CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  |  | 
|  | if (PosixConfig::ConfigValueExists(PosixConfig::kCounterKey_RebootCount)) | 
|  | { | 
|  | err = GetRebootCount(rebootCount); | 
|  | SuccessOrExit(err); | 
|  |  | 
|  | err = StoreRebootCount(rebootCount + 1); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  | else | 
|  | { | 
|  | // The first boot after factory reset of the Node. | 
|  | err = StoreRebootCount(1); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  |  | 
|  | if (!PosixConfig::ConfigValueExists(PosixConfig::kCounterKey_TotalOperationalHours)) | 
|  | { | 
|  | err = StoreTotalOperationalHours(0); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  |  | 
|  | if (!PosixConfig::ConfigValueExists(PosixConfig::kCounterKey_BootReason)) | 
|  | { | 
|  | err = StoreBootReason(to_underlying(BootReasonType::kUnspecified)); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  |  | 
|  | if (!PosixConfig::ConfigValueExists(PosixConfig::kConfigKey_RegulatoryLocation)) | 
|  | { | 
|  | uint32_t location = to_underlying(chip::app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kIndoor); | 
|  | err               = WriteConfigValue(PosixConfig::kConfigKey_RegulatoryLocation, location); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  |  | 
|  | if (!PosixConfig::ConfigValueExists(PosixConfig::kConfigKey_LocationCapability)) | 
|  | { | 
|  | uint32_t location = to_underlying(chip::app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kIndoorOutdoor); | 
|  | err               = WriteConfigValue(PosixConfig::kConfigKey_LocationCapability, location); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  |  | 
|  | if (!PosixConfig::ConfigValueExists(PosixConfig::kConfigKey_ConfigurationVersion)) | 
|  | { | 
|  | // The first boot after factory reset of the Node. | 
|  | err = StoreConfigurationVersion(1); | 
|  | SuccessOrExit(err); | 
|  | } | 
|  |  | 
|  | err = CHIP_NO_ERROR; | 
|  |  | 
|  | exit: | 
|  | return err; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::GetPrimaryWiFiMACAddress(uint8_t * buf) | 
|  | { | 
|  | struct ifaddrs * addresses = nullptr; | 
|  | struct sockaddr_ll * mac   = nullptr; | 
|  | CHIP_ERROR error           = CHIP_NO_ERROR; | 
|  |  | 
|  | // TODO: ideally the buffer size should have been passed as a span, however | 
|  | //       for now use the size that is validated in GenericConfigurationManagerImpl.ipp | 
|  | constexpr size_t kExpectedBufMinSize = ConfigurationManager::kPrimaryMACAddressLength; | 
|  | memset(buf, 0, kExpectedBufMinSize); | 
|  |  | 
|  | // Prioritize address for interface matching the WiFi interface name | 
|  | // specified in the config headers. Otherwise, use the address for the | 
|  | // first non-loopback interface. | 
|  | VerifyOrExit(getifaddrs(&addresses) == 0, error = CHIP_ERROR_INTERNAL); | 
|  | for (auto addr = addresses; addr != nullptr; addr = addr->ifa_next) | 
|  | { | 
|  | if ((addr->ifa_addr) && (addr->ifa_addr->sa_family == AF_PACKET)) | 
|  | { | 
|  | if (strncmp(addr->ifa_name, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, Inet::InterfaceId::kMaxIfNameLength) == 0) | 
|  | { | 
|  | mac = (struct sockaddr_ll *) addr->ifa_addr; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (strncmp(addr->ifa_name, "lo", Inet::InterfaceId::kMaxIfNameLength) != 0 && !mac) | 
|  | { | 
|  | mac = (struct sockaddr_ll *) addr->ifa_addr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (mac) | 
|  | { | 
|  | memcpy(buf, mac->sll_addr, std::min<size_t>(mac->sll_halen, kExpectedBufMinSize)); | 
|  | } | 
|  | else | 
|  | { | 
|  | error = CHIP_ERROR_NO_ENDPOINT; | 
|  | } | 
|  |  | 
|  | freeifaddrs(addresses); | 
|  |  | 
|  | exit: | 
|  | return error; | 
|  | } | 
|  |  | 
|  | bool ConfigurationManagerImpl::CanFactoryReset() | 
|  | { | 
|  | // TODO(#742): query the application to determine if factory reset is allowed. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void ConfigurationManagerImpl::InitiateFactoryReset() | 
|  | { | 
|  | PlatformMgr().ScheduleWork(DoFactoryReset); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t & value) | 
|  | { | 
|  | PosixConfig::Key configKey{ PosixConfig::kConfigNamespace_ChipCounters, key }; | 
|  |  | 
|  | CHIP_ERROR err = ReadConfigValue(configKey, value); | 
|  | if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) | 
|  | { | 
|  | err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; | 
|  | } | 
|  | return err; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t value) | 
|  | { | 
|  | PosixConfig::Key configKey{ PosixConfig::kConfigNamespace_ChipCounters, key }; | 
|  | return WriteConfigValue(configKey, value); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, bool & val) | 
|  | { | 
|  | return PosixConfig::ReadConfigValue(key, val); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint16_t & val) | 
|  | { | 
|  | return PosixConfig::ReadConfigValue(key, val); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint32_t & val) | 
|  | { | 
|  | return PosixConfig::ReadConfigValue(key, val); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint64_t & val) | 
|  | { | 
|  | return PosixConfig::ReadConfigValue(key, val); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) | 
|  | { | 
|  | return PosixConfig::ReadConfigValueStr(key, buf, bufSize, outLen); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) | 
|  | { | 
|  | return PosixConfig::ReadConfigValueBin(key, buf, bufSize, outLen); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, bool val) | 
|  | { | 
|  | return PosixConfig::WriteConfigValue(key, val); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint16_t val) | 
|  | { | 
|  | return PosixConfig::WriteConfigValue(key, val); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint32_t val) | 
|  | { | 
|  | return PosixConfig::WriteConfigValue(key, val); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint64_t val) | 
|  | { | 
|  | return PosixConfig::WriteConfigValue(key, val); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueStr(Key key, const char * str) | 
|  | { | 
|  | return PosixConfig::WriteConfigValueStr(key, str); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueStr(Key key, const char * str, size_t strLen) | 
|  | { | 
|  | return PosixConfig::WriteConfigValueStr(key, str, strLen); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) | 
|  | { | 
|  | return PosixConfig::WriteConfigValueBin(key, data, dataLen); | 
|  | } | 
|  |  | 
|  | void ConfigurationManagerImpl::RunConfigUnitTest() | 
|  | { | 
|  | PosixConfig::RunConfigUnitTest(); | 
|  | } | 
|  |  | 
|  | void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) | 
|  | { | 
|  | CHIP_ERROR err; | 
|  |  | 
|  | ChipLogProgress(DeviceLayer, "Performing factory reset"); | 
|  |  | 
|  | err = PosixConfig::FactoryResetConfig(); | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | ChipLogError(DeviceLayer, "Failed to factory reset configurations: %s", ErrorStr(err)); | 
|  | } | 
|  |  | 
|  | err = PosixConfig::FactoryResetCounters(); | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | ChipLogError(DeviceLayer, "Failed to factory reset counters: %s", ErrorStr(err)); | 
|  | } | 
|  |  | 
|  | #if CHIP_DEVICE_CONFIG_ENABLE_THREAD | 
|  |  | 
|  | ChipLogProgress(DeviceLayer, "Clearing Thread provision"); | 
|  | ThreadStackMgr().ErasePersistentInfo(); | 
|  |  | 
|  | #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD | 
|  |  | 
|  | // Restart the system. | 
|  | ChipLogProgress(DeviceLayer, "System restarting (not implemented)"); | 
|  | // TODO(#742): restart CHIP exe | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::StoreVendorId(uint16_t vendorId) | 
|  | { | 
|  | return WriteConfigValue(PosixConfig::kConfigKey_VendorId, vendorId); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::StoreProductId(uint16_t productId) | 
|  | { | 
|  | return WriteConfigValue(PosixConfig::kConfigKey_ProductId, productId); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::GetRebootCount(uint32_t & rebootCount) | 
|  | { | 
|  | return ReadConfigValue(PosixConfig::kCounterKey_RebootCount, rebootCount); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::StoreRebootCount(uint32_t rebootCount) | 
|  | { | 
|  | return WriteConfigValue(PosixConfig::kCounterKey_RebootCount, rebootCount); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) | 
|  | { | 
|  | return ReadConfigValue(PosixConfig::kCounterKey_TotalOperationalHours, totalOperationalHours); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours) | 
|  | { | 
|  | return WriteConfigValue(PosixConfig::kCounterKey_TotalOperationalHours, totalOperationalHours); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::GetBootReason(uint32_t & bootReason) | 
|  | { | 
|  | return ReadConfigValue(PosixConfig::kCounterKey_BootReason, bootReason); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::StoreBootReason(uint32_t bootReason) | 
|  | { | 
|  | return WriteConfigValue(PosixConfig::kCounterKey_BootReason, bootReason); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::GetRegulatoryLocation(uint8_t & location) | 
|  | { | 
|  | uint32_t value; | 
|  |  | 
|  | if (CHIP_NO_ERROR != ReadConfigValue(PosixConfig::kConfigKey_RegulatoryLocation, value)) | 
|  | { | 
|  | ReturnErrorOnFailure(GetLocationCapability(location)); | 
|  |  | 
|  | if (CHIP_NO_ERROR != StoreRegulatoryLocation(location)) | 
|  | { | 
|  | ChipLogError(DeviceLayer, "Failed to store RegulatoryLocation"); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | location = static_cast<uint8_t>(value); | 
|  | } | 
|  |  | 
|  | return CHIP_NO_ERROR; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::GetLocationCapability(uint8_t & location) | 
|  | { | 
|  | uint32_t value = 0; | 
|  |  | 
|  | CHIP_ERROR err = ReadConfigValue(PosixConfig::kConfigKey_LocationCapability, value); | 
|  |  | 
|  | if (err == CHIP_NO_ERROR) | 
|  | { | 
|  | VerifyOrReturnError(value <= UINT8_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); | 
|  | location = static_cast<uint8_t>(value); | 
|  | } | 
|  |  | 
|  | return err; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::GetConfigurationVersion(uint32_t & configurationVersion) | 
|  | { | 
|  | return ReadConfigValue(PosixConfig::kConfigKey_ConfigurationVersion, configurationVersion); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR ConfigurationManagerImpl::StoreConfigurationVersion(uint32_t configurationVersion) | 
|  | { | 
|  | return WriteConfigValue(PosixConfig::kConfigKey_ConfigurationVersion, configurationVersion); | 
|  | } | 
|  |  | 
|  | ConfigurationManager & ConfigurationMgrImpl() | 
|  | { | 
|  | return ConfigurationManagerImpl::GetDefaultInstance(); | 
|  | } | 
|  |  | 
|  | } // namespace DeviceLayer | 
|  | } // namespace chip |