| /* |
| * |
| * 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. |
| */ |
| |
| #include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h> |
| #include <Weave/DeviceLayer/internal/DeviceNetworkInfo.h> |
| #include <Weave/Core/WeaveTLV.h> |
| #include <Weave/Profiles/WeaveProfiles.h> |
| |
| using namespace ::nl; |
| using namespace ::nl::Weave; |
| using namespace ::nl::Weave::TLV; |
| using namespace ::nl::Weave::Profiles::NetworkProvisioning; |
| |
| using Profiles::kWeaveProfile_NetworkProvisioning; |
| |
| namespace nl { |
| namespace Weave { |
| namespace DeviceLayer { |
| namespace Internal { |
| |
| void DeviceNetworkInfo::Reset() |
| { |
| memset(this, 0, sizeof(*this)); |
| NetworkType = kNetworkType_NotSpecified; |
| #if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| WiFiMode = kWiFiMode_NotSpecified; |
| WiFiRole = kWiFiRole_NotSpecified; |
| WiFiSecurityType = kWiFiSecurityType_NotSpecified; |
| #endif // WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| #if WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| ThreadPANId = kThreadPANId_NotSpecified; |
| ThreadChannel = kThreadChannel_NotSpecified; |
| #endif // WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| WirelessSignalStrength = INT16_MIN; |
| } |
| |
| WEAVE_ERROR DeviceNetworkInfo::Encode(nl::Weave::TLV::TLVWriter & writer) const |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| TLVType outerContainer; |
| |
| uint64_t tag = (writer.GetContainerType() == kTLVType_Array) |
| ? AnonymousTag |
| : ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_NetworkInformation); |
| |
| err = writer.StartContainer(tag, kTLVType_Structure, outerContainer); |
| SuccessOrExit(err); |
| |
| if (FieldPresent.NetworkId) |
| { |
| err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_NetworkId), (uint32_t) NetworkId); |
| SuccessOrExit(err); |
| } |
| |
| if (NetworkType != kNetworkType_NotSpecified) |
| { |
| err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_NetworkType), (uint32_t) NetworkType); |
| SuccessOrExit(err); |
| } |
| |
| #if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| |
| if (WiFiSSID[0] != 0) |
| { |
| err = writer.PutString(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_WiFiSSID), WiFiSSID); |
| SuccessOrExit(err); |
| } |
| |
| if (WiFiMode != kWiFiMode_NotSpecified) |
| { |
| err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_WiFiMode), (uint32_t) WiFiMode); |
| SuccessOrExit(err); |
| } |
| |
| if (WiFiRole != kWiFiRole_NotSpecified) |
| { |
| err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_WiFiRole), (uint32_t) WiFiRole); |
| SuccessOrExit(err); |
| } |
| |
| if (WiFiSecurityType != kWiFiSecurityType_NotSpecified) |
| { |
| err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_WiFiSecurityType), (uint32_t) WiFiSecurityType); |
| SuccessOrExit(err); |
| } |
| |
| if (WiFiKeyLen != 0) |
| { |
| err = writer.PutBytes(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_WiFiPreSharedKey), WiFiKey, WiFiKeyLen); |
| SuccessOrExit(err); |
| } |
| |
| #endif // WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| |
| #if WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| |
| if (ThreadNetworkName[0] != 0) |
| { |
| err = writer.PutString(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadNetworkName), ThreadNetworkName); |
| SuccessOrExit(err); |
| } |
| |
| if (FieldPresent.ThreadExtendedPANId) |
| { |
| err = writer.PutBytes(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadExtendedPANId), |
| ThreadExtendedPANId, kThreadExtendedPANIdLength); |
| SuccessOrExit(err); |
| } |
| |
| if (FieldPresent.ThreadMeshPrefix) |
| { |
| err = writer.PutBytes(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadMeshPrefix), |
| ThreadMeshPrefix, kThreadMeshPrefixLength); |
| SuccessOrExit(err); |
| } |
| |
| if (FieldPresent.ThreadNetworkKey) |
| { |
| err = writer.PutBytes(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadNetworkKey), |
| ThreadNetworkKey, kThreadNetworkKeyLength); |
| SuccessOrExit(err); |
| } |
| |
| if (FieldPresent.ThreadPSKc) |
| { |
| err = writer.PutBytes(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadPSKc), |
| ThreadPSKc, kThreadPSKcLength); |
| SuccessOrExit(err); |
| } |
| |
| if (ThreadPANId != kThreadPANId_NotSpecified) |
| { |
| VerifyOrExit(ThreadPANId <= UINT16_MAX, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadPANId), ThreadPANId); |
| SuccessOrExit(err); |
| } |
| |
| if (ThreadChannel != kThreadChannel_NotSpecified) |
| { |
| err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadChannel), ThreadChannel); |
| SuccessOrExit(err); |
| } |
| |
| #endif // WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| |
| if (WirelessSignalStrength != INT16_MIN) |
| { |
| err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_WirelessSignalStrength), WirelessSignalStrength); |
| SuccessOrExit(err); |
| } |
| |
| err = writer.EndContainer(outerContainer); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceNetworkInfo::Decode(nl::Weave::TLV::TLVReader & reader) |
| { |
| WEAVE_ERROR err; |
| TLVType outerContainer; |
| uint32_t val; |
| |
| if (reader.GetType() == kTLVType_NotSpecified) |
| { |
| err = reader.Next(); |
| SuccessOrExit(err); |
| } |
| |
| VerifyOrExit(reader.GetTag() == ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_NetworkInformation) || |
| reader.GetTag() == AnonymousTag, |
| err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| |
| VerifyOrExit(reader.GetType() == kTLVType_Structure, err = WEAVE_ERROR_WRONG_TLV_TYPE); |
| |
| err = reader.EnterContainer(outerContainer); |
| SuccessOrExit(err); |
| |
| Reset(); |
| |
| while ((err = reader.Next()) == WEAVE_NO_ERROR) |
| { |
| uint64_t elemTag = reader.GetTag(); |
| |
| if (!IsProfileTag(elemTag) || ProfileIdFromTag(elemTag) != kWeaveProfile_NetworkProvisioning) |
| continue; |
| |
| switch (TagNumFromTag(elemTag)) |
| { |
| case kTag_NetworkId: |
| VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.Get(NetworkId); |
| SuccessOrExit(err); |
| FieldPresent.NetworkId = true; |
| break; |
| case kTag_NetworkType: |
| VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.Get(val); |
| SuccessOrExit(err); |
| NetworkType = (NetworkType_t) val; |
| break; |
| case kTag_WirelessSignalStrength: |
| VerifyOrExit(reader.GetType() == kTLVType_SignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.Get(WirelessSignalStrength); |
| SuccessOrExit(err); |
| break; |
| #if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| case kTag_WiFiSSID: |
| VerifyOrExit(reader.GetType() == kTLVType_UTF8String, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.GetString(WiFiSSID, sizeof(WiFiSSID)); |
| SuccessOrExit(err); |
| break; |
| case kTag_WiFiMode: |
| VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.Get(val); |
| SuccessOrExit(err); |
| WiFiMode = (WiFiMode_t) val; |
| break; |
| case kTag_WiFiRole: |
| VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.Get(val); |
| SuccessOrExit(err); |
| WiFiRole = (WiFiRole_t) val; |
| break; |
| case kTag_WiFiPreSharedKey: |
| VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| val = reader.GetLength(); |
| VerifyOrExit(val <= kMaxWiFiKeyLength, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| WiFiKeyLen = (uint16_t)val; |
| err = reader.GetBytes(WiFiKey, sizeof(WiFiKey)); |
| SuccessOrExit(err); |
| break; |
| case kTag_WiFiSecurityType: |
| VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.Get(val); |
| SuccessOrExit(err); |
| WiFiSecurityType = (WiFiSecurityType_t) val; |
| break; |
| #else // WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| case kTag_WiFiSSID: |
| case kTag_WiFiMode: |
| case kTag_WiFiRole: |
| case kTag_WiFiPreSharedKey: |
| case kTag_WiFiSecurityType: |
| ExitNow(err = WEAVE_ERROR_UNSUPPORTED_WEAVE_FEATURE); |
| break; |
| #endif //WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| #if WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| case kTag_ThreadNetworkName: |
| VerifyOrExit(reader.GetType() == kTLVType_UTF8String, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.GetString(ThreadNetworkName, sizeof(ThreadNetworkName)); |
| SuccessOrExit(err); |
| break; |
| case kTag_ThreadExtendedPANId: |
| VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| val = reader.GetLength(); |
| VerifyOrExit(val == kThreadExtendedPANIdLength, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.GetBytes(ThreadExtendedPANId, sizeof(ThreadExtendedPANId)); |
| SuccessOrExit(err); |
| FieldPresent.ThreadExtendedPANId = true; |
| break; |
| case kTag_ThreadMeshPrefix: |
| VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| val = reader.GetLength(); |
| VerifyOrExit(val == kThreadMeshPrefixLength, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.GetBytes(ThreadMeshPrefix, sizeof(ThreadMeshPrefix)); |
| SuccessOrExit(err); |
| FieldPresent.ThreadMeshPrefix = true; |
| break; |
| case kTag_ThreadNetworkKey: |
| VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| val = reader.GetLength(); |
| VerifyOrExit(val == kThreadNetworkKeyLength, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.GetBytes(ThreadNetworkKey, sizeof(ThreadNetworkKey)); |
| SuccessOrExit(err); |
| FieldPresent.ThreadNetworkKey = true; |
| break; |
| case kTag_ThreadPSKc: |
| VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| val = reader.GetLength(); |
| VerifyOrExit(val == kThreadPSKcLength, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.GetBytes(ThreadPSKc, sizeof(ThreadPSKc)); |
| SuccessOrExit(err); |
| FieldPresent.ThreadPSKc = true; |
| break; |
| case kTag_ThreadPANId: |
| VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.Get(val); |
| SuccessOrExit(err); |
| VerifyOrExit(val <= UINT16_MAX, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| ThreadPANId = val; |
| break; |
| case kTag_ThreadChannel: |
| VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| err = reader.Get(val); |
| SuccessOrExit(err); |
| VerifyOrExit(val <= UINT8_MAX, err = WEAVE_ERROR_INVALID_TLV_ELEMENT); |
| ThreadChannel = val; |
| break; |
| #else // WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| case kTag_ThreadNetworkName: |
| case kTag_ThreadExtendedPANId: |
| case kTag_ThreadMeshPrefix: |
| case kTag_ThreadNetworkKey: |
| case kTag_ThreadPSKc: |
| case kTag_ThreadPANId: |
| case kTag_ThreadChannel: |
| ExitNow(err = WEAVE_ERROR_UNSUPPORTED_WEAVE_FEATURE); |
| break; |
| #endif // WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| default: |
| // Ignore unknown elements for compatibility with future formats. |
| break; |
| } |
| } |
| |
| if (err != WEAVE_END_OF_TLV) |
| ExitNow(); |
| |
| err = reader.ExitContainer(outerContainer); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceNetworkInfo::MergeTo(DeviceNetworkInfo & dest) |
| { |
| if (NetworkType != kNetworkType_NotSpecified) |
| { |
| dest.NetworkType = NetworkType; |
| } |
| if (FieldPresent.NetworkId) |
| { |
| dest.NetworkId = NetworkId; |
| dest.FieldPresent.NetworkId = true; |
| } |
| |
| #if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| if (WiFiSSID[0] != 0) |
| { |
| memcpy(dest.WiFiSSID, WiFiSSID, sizeof(WiFiSSID)); |
| } |
| if (WiFiMode != kWiFiMode_NotSpecified) |
| { |
| dest.WiFiMode = WiFiMode; |
| } |
| if (WiFiRole != kWiFiRole_NotSpecified) |
| { |
| dest.WiFiRole = WiFiRole; |
| } |
| if (WiFiSecurityType != kWiFiSecurityType_NotSpecified) |
| { |
| dest.WiFiSecurityType = WiFiSecurityType; |
| } |
| if (WiFiKeyLen != 0) |
| { |
| memcpy(dest.WiFiKey, WiFiKey, WiFiKeyLen); |
| dest.WiFiKeyLen = WiFiKeyLen; |
| } |
| #endif // WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| |
| #if WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| if (ThreadNetworkName[0] != 0) |
| { |
| memcpy(dest.ThreadNetworkName, ThreadNetworkName, sizeof(ThreadNetworkName)); |
| } |
| if (FieldPresent.ThreadExtendedPANId) |
| { |
| memcpy(dest.ThreadExtendedPANId, ThreadExtendedPANId, sizeof(ThreadExtendedPANId)); |
| } |
| if (FieldPresent.ThreadMeshPrefix) |
| { |
| memcpy(dest.ThreadMeshPrefix, ThreadMeshPrefix, sizeof(ThreadMeshPrefix)); |
| } |
| if (FieldPresent.ThreadNetworkKey) |
| { |
| memcpy(dest.ThreadNetworkKey, ThreadNetworkKey, sizeof(ThreadNetworkKey)); |
| } |
| if (FieldPresent.ThreadPSKc) |
| { |
| memcpy(dest.ThreadPSKc, ThreadPSKc, sizeof(ThreadPSKc)); |
| } |
| if (ThreadPANId != kThreadPANId_NotSpecified) |
| { |
| dest.ThreadPANId = ThreadPANId; |
| } |
| if (ThreadChannel != kThreadChannel_NotSpecified) |
| { |
| dest.ThreadChannel = ThreadChannel; |
| } |
| #endif // WEAVE_DEVICE_CONFIG_ENABLE_THREAD |
| |
| if (WirelessSignalStrength != INT16_MIN) |
| { |
| dest.WirelessSignalStrength = WirelessSignalStrength; |
| } |
| |
| return WEAVE_NO_ERROR; |
| } |
| |
| WEAVE_ERROR DeviceNetworkInfo::EncodeArray(nl::Weave::TLV::TLVWriter & writer, const DeviceNetworkInfo * elems, size_t count) |
| { |
| WEAVE_ERROR err; |
| TLVType outerContainerType; |
| |
| err = writer.StartContainer(AnonymousTag, kTLVType_Array, outerContainerType); |
| SuccessOrExit(err); |
| |
| for (size_t i = 0; i < count; i++) |
| { |
| err = elems[i].Encode(writer); |
| SuccessOrExit(err); |
| } |
| |
| err = writer.EndContainer(outerContainerType); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| } // namespace Internal |
| } // namespace DeviceLayer |
| } // namespace Weave |
| } // namespace nl |