blob: b7f19a77eb56ba6628434f9e8e4277f07363f654 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* 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 <core/CHIPEncoding.h>
#include <core/CHIPSafeCasts.h>
#include <platform/internal/DeviceNetworkInfo.h>
#include <protocols/CHIPProtocols.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/SafeInt.h>
#include <transport/NetworkProvisioning.h>
#if CONFIG_DEVICE_LAYER
#include <platform/CHIPDeviceLayer.h>
#endif
namespace chip {
void NetworkProvisioning::Init(NetworkProvisioningDelegate * delegate, DeviceNetworkProvisioningDelegate * deviceDelegate)
{
if (mDelegate != nullptr)
{
mDelegate->Release();
}
if (delegate != nullptr)
{
mDelegate = delegate->Retain();
}
if (mDeviceDelegate != nullptr)
{
mDeviceDelegate->Release();
}
if (deviceDelegate != nullptr)
{
mDeviceDelegate = deviceDelegate->Retain();
#if CONFIG_DEVICE_LAYER
DeviceLayer::PlatformMgr().AddEventHandler(ConnectivityHandler, reinterpret_cast<intptr_t>(this));
#endif
}
}
NetworkProvisioning::~NetworkProvisioning()
{
if (mDeviceDelegate != nullptr)
{
mDeviceDelegate->Release();
#if CONFIG_DEVICE_LAYER
DeviceLayer::PlatformMgr().RemoveEventHandler(ConnectivityHandler, reinterpret_cast<intptr_t>(this));
#endif
}
if (mDelegate != nullptr)
{
mDelegate->Release();
}
}
CHIP_ERROR NetworkProvisioning::HandleNetworkProvisioningMessage(uint8_t msgType, System::PacketBuffer * msgBuf)
{
CHIP_ERROR err = CHIP_NO_ERROR;
switch (msgType)
{
case NetworkProvisioning::MsgTypes::kWiFiAssociationRequest: {
char SSID[chip::DeviceLayer::Internal::kMaxWiFiSSIDLength];
char passwd[chip::DeviceLayer::Internal::kMaxWiFiKeyLength];
BufBound bbufSSID(Uint8::from_char(SSID), chip::DeviceLayer::Internal::kMaxWiFiSSIDLength);
BufBound bbufPW(Uint8::from_char(passwd), chip::DeviceLayer::Internal::kMaxWiFiKeyLength);
const uint8_t * buffer = msgBuf->Start();
size_t len = msgBuf->DataLength();
size_t offset = 0;
ChipLogProgress(NetworkProvisioning, "Received kWiFiAssociationRequest. DeviceDelegate %p\n", mDeviceDelegate);
VerifyOrExit(mDeviceDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
err = DecodeString(&buffer[offset], len - offset, bbufSSID, offset);
// TODO: Check for the error once network provisioning is moved to delegate calls
err = DecodeString(&buffer[offset], len - offset, bbufPW, offset);
// TODO: Check for the error once network provisioning is moved to delegate calls
mDeviceDelegate->ProvisionNetwork(SSID, passwd);
err = CHIP_NO_ERROR;
}
break;
case NetworkProvisioning::MsgTypes::kIPAddressAssigned: {
ChipLogProgress(NetworkProvisioning, "Received kIPAddressAssigned\n");
if (!Inet::IPAddress::FromString(Uint8::to_const_char(msgBuf->Start()), msgBuf->DataLength(), mDeviceAddress))
{
ExitNow(err = CHIP_ERROR_INVALID_ADDRESS);
}
}
break;
default:
ExitNow(err = CHIP_ERROR_INVALID_MESSAGE_TYPE);
break;
};
exit:
if (mDelegate != nullptr)
{
if (err != CHIP_NO_ERROR)
{
ChipLogError(NetworkProvisioning, "Failed in HandleNetworkProvisioningMessage. error %s\n", ErrorStr(err));
mDelegate->OnNetworkProvisioningError(err);
}
else
{
// Network provisioning handshake requires only one message exchange in either direction.
// If the current message handling did not result in an error, network provisioning is
// complete.
mDelegate->OnNetworkProvisioningComplete();
}
}
return err;
}
CHIP_ERROR NetworkProvisioning::EncodeString(const char * str, BufBound & bbuf)
{
CHIP_ERROR err = CHIP_NO_ERROR;
size_t length = strlen(str);
uint16_t u16len = static_cast<uint16_t>(length);
VerifyOrExit(CanCastTo<uint16_t>(length), err = CHIP_ERROR_INVALID_ARGUMENT);
bbuf.PutLE16(u16len);
bbuf.Put(str);
exit:
return err;
}
CHIP_ERROR NetworkProvisioning::DecodeString(const uint8_t * input, size_t input_len, BufBound & bbuf, size_t & consumed)
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint16_t length = 0;
VerifyOrExit(input_len >= sizeof(uint16_t), err = CHIP_ERROR_BUFFER_TOO_SMALL);
length = chip::Encoding::LittleEndian::Get16(input);
consumed = sizeof(uint16_t);
VerifyOrExit(input_len - consumed >= length, err = CHIP_ERROR_BUFFER_TOO_SMALL);
bbuf.Put(&input[consumed], length);
consumed += bbuf.Written();
bbuf.Put('\0');
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_BUFFER_TOO_SMALL);
exit:
return err;
}
CHIP_ERROR NetworkProvisioning::SendIPAddress(const Inet::IPAddress & addr)
{
CHIP_ERROR err = CHIP_NO_ERROR;
System::PacketBuffer * buffer = System::PacketBuffer::New();
char * addrStr = addr.ToString(Uint8::to_char(buffer->Start()), buffer->AvailableDataLength());
size_t addrLen = 0;
ChipLogProgress(NetworkProvisioning, "Sending IP Address. Delegate %p\n", mDelegate);
VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(addrStr != nullptr, err = CHIP_ERROR_INVALID_ADDRESS);
addrLen = strlen(addrStr) + 1;
VerifyOrExit(CanCastTo<uint16_t>(addrLen), err = CHIP_ERROR_INVALID_ARGUMENT);
buffer->SetDataLength(static_cast<uint16_t>(addrLen));
err = mDelegate->SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning,
NetworkProvisioning::MsgTypes::kIPAddressAssigned, buffer);
SuccessOrExit(err);
exit:
if (CHIP_NO_ERROR != err)
{
ChipLogError(NetworkProvisioning, "Failed in sending IP address. error %s\n", ErrorStr(err));
System::PacketBuffer::Free(buffer);
}
return err;
}
CHIP_ERROR NetworkProvisioning::SendNetworkCredentials(const char * ssid, const char * passwd)
{
CHIP_ERROR err = CHIP_NO_ERROR;
System::PacketBuffer * buffer = System::PacketBuffer::New();
BufBound bbuf(buffer->Start(), buffer->TotalLength());
ChipLogProgress(NetworkProvisioning, "Sending Network Creds. Delegate %p\n", mDelegate);
VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
SuccessOrExit(EncodeString(ssid, bbuf));
SuccessOrExit(EncodeString(passwd, bbuf));
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_BUFFER_TOO_SMALL);
VerifyOrExit(CanCastTo<uint16_t>(bbuf.Written()), err = CHIP_ERROR_INVALID_ARGUMENT);
buffer->SetDataLength(static_cast<uint16_t>(bbuf.Written()));
err = mDelegate->SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning,
NetworkProvisioning::MsgTypes::kWiFiAssociationRequest, buffer);
SuccessOrExit(err);
exit:
if (CHIP_NO_ERROR != err)
{
ChipLogError(NetworkProvisioning, "Failed in sending Network Creds. error %s\n", ErrorStr(err));
System::PacketBuffer::Free(buffer);
}
return err;
}
#if CONFIG_DEVICE_LAYER
void NetworkProvisioning::ConnectivityHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
{
NetworkProvisioning * session = reinterpret_cast<NetworkProvisioning *>(arg);
VerifyOrExit(session != nullptr, /**/);
VerifyOrExit(event->Type == DeviceLayer::DeviceEventType::kInternetConnectivityChange, /**/);
VerifyOrExit(event->InternetConnectivityChange.IPv4 == DeviceLayer::kConnectivity_Established, /**/);
Inet::IPAddress addr;
Inet::IPAddress::FromString(event->InternetConnectivityChange.address, addr);
(void) session->SendIPAddress(addr);
exit:
return;
}
#endif
} // namespace chip