blob: bf483667a5231e6d9a0850a63007f46981718f14 [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 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.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <Weave/Core/WeaveCore.h>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Core/WeaveEncoding.h>
#include <Weave/Profiles/WeaveProfiles.h>
#include "NetworkInfo.h"
namespace nl {
namespace Weave {
namespace Profiles {
namespace NetworkProvisioning {
using namespace nl::Weave::Encoding;
using namespace nl::Weave::TLV;
NetworkInfo::NetworkInfo()
{
NetworkType = kNetworkType_NotSpecified;
NetworkId = -1;
WiFiSSID = NULL;
WiFiMode = kWiFiMode_NotSpecified;
WiFiRole = kWiFiRole_NotSpecified;
WiFiSecurityType = kWiFiSecurityType_NotSpecified;
WiFiKey = NULL;
WiFiKeyLen = 0;
Hidden = false;
ThreadNetworkName = NULL;
ThreadExtendedPANId = NULL;
ThreadNetworkKey = NULL;
ThreadNetworkKeyLen = 0;
WirelessSignalStrength = INT16_MIN;
}
NetworkInfo::~NetworkInfo()
{
Clear();
}
static WEAVE_ERROR ReplaceValue(char *& dest, const char *src)
{
#if HAVE_MALLOC && HAVE_STRDUP && HAVE_FREE
if (dest != NULL)
free((void *) dest);
if (src != NULL)
{
dest = strdup(src);
return dest != NULL ? WEAVE_NO_ERROR : WEAVE_ERROR_NO_MEMORY;
}
else
{
dest = NULL;
return WEAVE_NO_ERROR;
}
#else
return WEAVE_ERROR_NOT_IMPLEMENTED;
#endif
}
static WEAVE_ERROR ReplaceValue(uint8_t *& dest, uint32_t& destLen, const uint8_t *src, uint32_t srcLen)
{
#if HAVE_MALLOC && HAVE_STRDUP && HAVE_FREE
if (dest != NULL)
free((void *) dest);
if (src != NULL)
{
dest = (uint8_t *) malloc(srcLen);
if (dest == NULL)
return WEAVE_ERROR_NO_MEMORY;
memcpy(dest, src, srcLen);
destLen = srcLen;
return WEAVE_NO_ERROR;
}
else
{
dest = NULL;
destLen = 0;
return WEAVE_NO_ERROR;
}
#else
return WEAVE_ERROR_NOT_IMPLEMENTED;
#endif
}
WEAVE_ERROR NetworkInfo::CopyTo(NetworkInfo& dest)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint32_t unused;
dest.NetworkType = NetworkType;
dest.NetworkId = NetworkId;
err = ReplaceValue(dest.WiFiSSID, WiFiSSID);
SuccessOrExit(err);
dest.WiFiMode = WiFiMode;
dest.WiFiRole = WiFiRole;
dest.WiFiSecurityType = WiFiSecurityType;
err = ReplaceValue(dest.WiFiKey, dest.WiFiKeyLen, WiFiKey, WiFiKeyLen);
SuccessOrExit(err);
err = ReplaceValue(dest.ThreadNetworkName, ThreadNetworkName);
SuccessOrExit(err);
err = ReplaceValue(dest.ThreadExtendedPANId, unused, ThreadExtendedPANId, 8);
SuccessOrExit(err);
err = ReplaceValue(dest.ThreadNetworkKey, dest.ThreadNetworkKeyLen, ThreadNetworkKey, ThreadNetworkKeyLen);
SuccessOrExit(err);
dest.WirelessSignalStrength = WirelessSignalStrength;
exit:
return err;
}
WEAVE_ERROR NetworkInfo::MergeTo(NetworkInfo& dest)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
if (NetworkType != kNetworkType_NotSpecified)
dest.NetworkType = NetworkType;
if (NetworkId != -1)
dest.NetworkId = NetworkId;
if (WiFiSSID != NULL)
{
err = ReplaceValue(dest.WiFiSSID, WiFiSSID);
SuccessOrExit(err);
}
if (WiFiMode != kWiFiMode_NotSpecified)
dest.WiFiMode = WiFiMode;
if (WiFiRole != kWiFiRole_NotSpecified)
dest.WiFiRole = WiFiRole;
if (WiFiSecurityType != kWiFiSecurityType_NotSpecified)
dest.WiFiSecurityType = WiFiSecurityType;
if (WiFiKey != NULL)
{
err = ReplaceValue(dest.WiFiKey, dest.WiFiKeyLen, WiFiKey, WiFiKeyLen);
SuccessOrExit(err);
}
if (ThreadNetworkName != NULL)
{
err = ReplaceValue(dest.ThreadNetworkName, ThreadNetworkName);
SuccessOrExit(err);
}
if (ThreadExtendedPANId != NULL)
{
uint32_t unused;
err = ReplaceValue(dest.ThreadExtendedPANId, unused, ThreadExtendedPANId, 8);
SuccessOrExit(err);
}
if (ThreadNetworkKey != NULL)
{
err = ReplaceValue(dest.ThreadNetworkKey, dest.ThreadNetworkKeyLen, ThreadNetworkKey, ThreadNetworkKeyLen);
SuccessOrExit(err);
}
if (WirelessSignalStrength != INT16_MIN)
dest.WirelessSignalStrength = WirelessSignalStrength;
exit:
return err;
}
WEAVE_ERROR NetworkInfo::Decode(nl::Weave::TLV::TLVReader& reader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVType outerContainer;
uint32_t val;
VerifyOrExit(reader.GetType() == kTLVType_Structure, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.EnterContainer(outerContainer);
SuccessOrExit(err);
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);
break;
case kTag_NetworkType:
VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.Get(val);
SuccessOrExit(err);
NetworkType = (::nl::Weave::Profiles::NetworkProvisioning::NetworkType) val;
break;
case kTag_WirelessSignalStrength:
VerifyOrExit(reader.GetType() == kTLVType_SignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.Get(WirelessSignalStrength);
SuccessOrExit(err);
break;
case kTag_WiFiSSID:
VerifyOrExit(reader.GetType() == kTLVType_UTF8String, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.DupString((char *&) 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 = (::nl::Weave::Profiles::NetworkProvisioning::WiFiMode) val;
break;
case kTag_WiFiRole:
VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.Get(val);
SuccessOrExit(err);
WiFiRole = (::nl::Weave::Profiles::NetworkProvisioning::WiFiRole) val;
break;
case kTag_WiFiSecurityType:
VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.Get(val);
SuccessOrExit(err);
WiFiSecurityType = (::nl::Weave::Profiles::NetworkProvisioning::WiFiSecurityType) val;
break;
case kTag_WiFiPreSharedKey:
VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.DupBytes(WiFiKey, WiFiKeyLen);
SuccessOrExit(err);
break;
case kTag_ThreadNetworkName:
VerifyOrExit(reader.GetType() == kTLVType_UTF8String, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.DupString(ThreadNetworkName);
SuccessOrExit(err);
break;
case kTag_ThreadExtendedPANId:
VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
VerifyOrExit(reader.GetLength() == 8, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.DupBytes(ThreadExtendedPANId, val);
SuccessOrExit(err);
break;
case kTag_ThreadNetworkKey:
VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
err = reader.DupBytes(ThreadNetworkKey, ThreadNetworkKeyLen);
SuccessOrExit(err);
break;
default:
// Ignore unknown elements
break;
}
}
if (err != WEAVE_END_OF_TLV)
ExitNow();
err = reader.ExitContainer(outerContainer);
SuccessOrExit(err);
exit:
if (err != WEAVE_NO_ERROR)
Clear();
return err;
}
WEAVE_ERROR NetworkInfo::Encode(nl::Weave::TLV::TLVWriter& writer, uint8_t encodeFlags) 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 (NetworkId != -1)
{
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 (WiFiSSID != NULL)
{
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 (WiFiKey != NULL && (encodeFlags & kEncodeFlag_EncodeCredentials) != 0)
{
err = writer.PutBytes(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_WiFiPreSharedKey), WiFiKey,
WiFiKeyLen);
SuccessOrExit(err);
}
if (ThreadNetworkName != NULL)
{
err = writer.PutString(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadNetworkName), ThreadNetworkName);
SuccessOrExit(err);
}
if (ThreadExtendedPANId != NULL)
{
err = writer.PutBytes(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadExtendedPANId), ThreadExtendedPANId, 8);
SuccessOrExit(err);
}
if (ThreadNetworkKey != NULL && (encodeFlags & kEncodeFlag_EncodeCredentials) != 0)
{
err = writer.PutBytes(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_ThreadNetworkKey), ThreadNetworkKey,
ThreadNetworkKeyLen);
SuccessOrExit(err);
}
if (WirelessSignalStrength != INT16_MIN)
{
err = writer.Put(ProfileTag(kWeaveProfile_NetworkProvisioning, kTag_WirelessSignalStrength),
WirelessSignalStrength);
SuccessOrExit(err);
}
err = writer.EndContainer(outerContainer);
SuccessOrExit(err);
exit:
return err;
}
void NetworkInfo::Clear()
{
NetworkType = kNetworkType_NotSpecified;
NetworkId = -1;
WiFiMode = kWiFiMode_NotSpecified;
WiFiRole = kWiFiRole_NotSpecified;
WiFiSecurityType = kWiFiSecurityType_NotSpecified;
WiFiKeyLen = 0;
ThreadNetworkKeyLen = 0;
WirelessSignalStrength = INT16_MIN;
#if HAVE_MALLOC && HAVE_FREE
if (WiFiSSID != NULL)
{
free((void *) WiFiSSID);
WiFiSSID = NULL;
}
if (WiFiKey != NULL)
{
free(WiFiKey);
WiFiKey = NULL;
}
if (ThreadNetworkName != NULL)
{
free((void *)ThreadNetworkName);
ThreadNetworkName = NULL;
}
if (ThreadExtendedPANId != NULL)
{
free((void *)ThreadExtendedPANId);
ThreadExtendedPANId = NULL;
}
if (ThreadNetworkKey != NULL)
{
free((void *)ThreadNetworkKey);
ThreadNetworkKey = NULL;
}
#endif //HAVE_MALLOC && HAVE_FREE
}
WEAVE_ERROR NetworkInfo::DecodeList(nl::Weave::TLV::TLVReader& reader, uint16_t& elemCount, NetworkInfo *& elemArray)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
NetworkInfo *newArray = NULL;
TLVType arrayOuter;
int i;
VerifyOrExit(reader.GetType() == kTLVType_Array, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.EnterContainer(arrayOuter);
SuccessOrExit(err);
if (elemArray == NULL)
{
#if HAVE_MALLOC && HAVE_FREE
elemArray = newArray = new NetworkInfo[elemCount];
#else
return WEAVE_ERROR_NOT_IMPLEMENTED;
#endif
}
for (i = 0; i < elemCount; i++)
{
err = reader.Next();
SuccessOrExit(err);
err = elemArray[i].Decode(reader);
SuccessOrExit(err);
}
err = reader.ExitContainer(arrayOuter);
SuccessOrExit(err);
elemCount = i;
return WEAVE_NO_ERROR;
exit:
#if HAVE_MALLOC && HAVE_FREE
if (newArray != NULL)
{
delete[] newArray;
elemArray = NULL;
}
#endif
return err;
}
WEAVE_ERROR NetworkInfo::EncodeList(nl::Weave::TLV::TLVWriter& writer, uint16_t elemCount, const NetworkInfo *elemArray, uint8_t encodeFlags)
{
WEAVE_ERROR err;
TLVType outerContainerType;
err = writer.StartContainer(AnonymousTag, kTLVType_Array, outerContainerType);
SuccessOrExit(err);
for (int i = 0; i < elemCount; i++)
{
err = elemArray[i].Encode(writer, encodeFlags);
SuccessOrExit(err);
}
err = writer.EndContainer(outerContainerType);
SuccessOrExit(err);
exit:
return err;
}
WEAVE_ERROR NetworkInfo::EncodeList(nl::Weave::TLV::TLVWriter& writer, uint16_t arrayLen, const NetworkInfo *elemArray,
::nl::Weave::Profiles::NetworkProvisioning::NetworkType networkType, uint8_t encodeFlags, uint16_t& encodedElemCount)
{
WEAVE_ERROR err;
TLVType outerContainerType;
encodedElemCount = 0;
err = writer.StartContainer(AnonymousTag, kTLVType_Array, outerContainerType);
SuccessOrExit(err);
for (int i = 0; i < arrayLen; i++)
if (elemArray[i].NetworkType != kNetworkType_NotSpecified &&
(networkType == kNetworkType_NotSpecified || elemArray[i].NetworkType == networkType))
{
err = elemArray[i].Encode(writer, encodeFlags);
SuccessOrExit(err);
encodedElemCount++;
}
err = writer.EndContainer(outerContainerType);
SuccessOrExit(err);
exit:
return err;
}
} // NetworkProvisioning
} // namespace Profiles
} // namespace Weave
} // namespace nl