blob: 09ea3a82dba1314a4b9011bbcf37fe8910706c95 [file] [log] [blame]
/*
*
* Copyright (c) 2021 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.
*/
#pragma once
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <lib/core/CHIPCore.h>
#include <lib/support/Span.h>
namespace chip {
namespace Thread {
class ThreadTLV;
inline constexpr size_t kChannel_NotSpecified = UINT8_MAX;
inline constexpr size_t kPANId_NotSpecified = UINT16_MAX;
/// The maximum size of a Thread operational dataset.
inline constexpr size_t kSizeOperationalDataset = 254;
inline constexpr size_t kSizeNetworkName = 16;
inline constexpr size_t kSizeExtendedPanId = 8;
inline constexpr size_t kSizeMasterKey = 16;
inline constexpr size_t kSizeMeshLocalPrefix = 8;
inline constexpr size_t kSizePSKc = 16;
class OperationalDataset;
/**
* This class provides a read-only view of a Thread operational dataset.
* The underlying data is not owned by this class, and must remain valid for the lifetime of the view.
*/
class OperationalDatasetView
{
public:
OperationalDatasetView() = default;
/**
* Initializes the dataset view with the given data.
* The data itself is not copied, so it must remain valid for the lifetime of the view.
*
* @param[in] aData The data to interpret as a Thread operational dataset.
*
* @retval CHIP_NO_ERROR Successfully initialized the dataset.
* @retval CHIP_ERROR_INVALID_ARGUMENT The dataset length @p aLength is too long or @p data is corrupted.
*/
CHIP_ERROR Init(ByteSpan aData);
/**
* Returns the ByteSpan underlying this view.
*/
ByteSpan AsByteSpan() const { return mData; }
/**
* Retrieves the Active Timestamp from the dataset.
*
* @param[out] aActiveTimestamp A reference to receive the active timestamp.
*
* @retval CHIP_NO_ERROR Successfully retrieved the active timestamp.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread active timestamp is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetActiveTimestamp(uint64_t & aActiveTimestamp) const;
/**
* Retrieves the channel number from the dataset.
*
* Note that the underlying TLV consists of a 1 byte Channel Page, and a 2 byte Channel Number.
* The Channel Page is not returned, as zero is currently the only valid value.
* A non-zero Channel Page is treated as a CHIP_ERROR_INVALID_TLV_ELEMENT error
*
* @param[out] aChannel A reference to receive the channel.
*
* @retval CHIP_NO_ERROR Successfully retrieved the channel.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread channel is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetChannel(uint16_t & aChannel) const;
/**
* Retrieves the Extended PAN ID from the dataset.
*
* @param[out] aExtendedPanId A reference to receive the extended PAN ID.
*
* @retval CHIP_NO_ERROR Successfully retrieved the extended PAN ID.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread extended PAN ID is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetExtendedPanId(uint8_t (&aExtendedPanId)[kSizeExtendedPanId]) const;
/**
* Retrieves the Extended PAN ID from the dataset, interpreted as a big endian number.
* @retval CHIP_NO_ERROR Successfully retrieved the extended PAN ID.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread extended PAN ID is not present in the dataset.
*/
CHIP_ERROR GetExtendedPanId(uint64_t & extendedPanId) const;
/**
* Retrieves a ByteSpan pointing to the Extended PAN ID within the dataset.
* This can be used to pass the extended PAN ID to a cluster command without the use of external memory.
*
* Note: The returned span points must not be dereferenced beyond the lifetime of this object.
*
* @param[out] span A reference to receive the location of the extended PAN ID.
*
* @retval CHIP_NO_ERROR Successfully retrieved the extended PAN ID.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread extended PAN ID is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetExtendedPanIdAsByteSpan(ByteSpan & span) const;
/**
* Retrieves the Master Key from the dataset.
*
* @param[out] aMasterKey A reference to receive the master key.
*
* @retval CHIP_NO_ERROR Successfully retrieved the master key.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread master key is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetMasterKey(uint8_t (&aMasterKey)[kSizeMasterKey]) const;
/**
* Retrieves the Mesh Local Prefix from the dataset.
*
* @param[out] aMeshLocalPrefix A reference to receive the mesh local prefix.
*
* @retval CHIP_NO_ERROR Successfully retrieved the mesh local prefix.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread mesh local prefix is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetMeshLocalPrefix(uint8_t (&aMeshLocalPrefix)[kSizeMeshLocalPrefix]) const;
/**
* Retrieves the Network Name from the dataset.
*
* @param[out] aNetworkName A reference to receive the Thread network name.
*
* @retval CHIP_NO_ERROR Successfully retrieved the network name.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread network name is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetNetworkName(char (&aNetworkName)[kSizeNetworkName + 1]) const;
/**
* Retrieves the PAN ID from the dataset.
*
* @param[out] aPanId A reference to receive the PAN ID.
*
* @retval CHIP_NO_ERROR Successfully retrieved the PAN ID.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread PAN ID is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetPanId(uint16_t & aPanId) const;
/**
* Retrieves the Pre-Shared Key for the Commissioner (PSKc) from the dataset.
*
* @param[out] aPSKc A reference to receive the PSKc.
*
* @retval CHIP_NO_ERROR Successfully retrieved the PSKc.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread PSKc is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
*/
CHIP_ERROR GetPSKc(uint8_t (&aPSKc)[kSizePSKc]) const;
/**
* Retrieves a ByteSpan pointing to the Channel Mask within the dataset.
*
* Note: The returned span must not be dereferenced beyond the lifetime of this object.
*
* @retval CHIP_NO_ERROR on success.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND if the channel mask is not present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT if the TLV element is invalid.
*/
CHIP_ERROR GetChannelMask(ByteSpan & aChannelMask) const;
/**
* Retrieves the Security Policy from the dataset.
*
* @retval CHIP_NO_ERROR on success.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND if no security policy is present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT if the TLV element is invalid.
*/
CHIP_ERROR GetSecurityPolicy(uint32_t & aSecurityPolicy) const;
/**
* Retrieves the Delay Timer from the dataset.
*
* @retval CHIP_NO_ERROR on success.
* @retval CHIP_ERROR_TLV_TAG_NOT_FOUND if no security policy is present in the dataset.
* @retval CHIP_ERROR_INVALID_TLV_ELEMENT if the TLV element is invalid.
*/
CHIP_ERROR GetDelayTimer(uint32_t & aDelayMillis) const;
/**
* Returns true if the dataset contains the required TLV elements for creating a Thread network.
* The required elements are: PAN ID, Extended PAN ID, Channel, and Master Key.
*/
bool IsCommissioned() const;
/**
* This method checks if the dataset is empty.
*/
bool IsEmpty() const { return mData.empty(); }
/**
* This method checks whether @p aData contains a valid sequence of Thread TLV elements.
*
* @note This method only verifies the overall TLV format, not the correctness of individual TLV elements.
*/
static bool IsValid(ByteSpan aData);
private:
friend class OperationalDataset;
ByteSpan mData;
OperationalDatasetView(uint8_t * buffer) : mData(ByteSpan(buffer, 0)) {}
const ThreadTLV * Locate(uint8_t aType) const;
bool Has(uint8_t aType) const { return Locate(aType) != nullptr; }
};
/**
* This class provides methods to manipulate a Thread operational dataset.
* It maintains an internal buffer sized to accommodate the maximum possible dataset size.
*/
class OperationalDataset : public OperationalDatasetView
{
public:
OperationalDataset() : OperationalDatasetView(mBuffer) {}
// Delegate copy construction and assignment to the overloads taking an OperationalDatasetView.
OperationalDataset(const OperationalDataset & other) : OperationalDataset(static_cast<const OperationalDatasetView &>(other)) {}
OperationalDataset & operator=(const OperationalDataset & other)
{
return *this = static_cast<const OperationalDatasetView &>(other);
}
OperationalDataset(const OperationalDatasetView & view) : OperationalDatasetView(view) { CopyData(); }
OperationalDataset & operator=(const OperationalDatasetView & view)
{
static_cast<OperationalDatasetView &>(*this) = view;
CopyData();
return *this;
}
/**
* Initializes the dataset by copying the provided data into an internal buffer.
*
* @param[in] aData The data to interpret as a Thread operational dataset.
*
* @retval CHIP_NO_ERROR Successfully initialized the dataset.
* @retval CHIP_ERROR_INVALID_ARGUMENT The dataset length @p aLength is too long or @p data is corrupted.
*/
CHIP_ERROR Init(ByteSpan aData);
/**
* Sets the Active Timestamp in the dataset.
*
* @param[in] aActiveTimestamp The Thread active timestamp.
*
* @retval CHIP_NO_ERROR Successfully set the active timestamp.
* @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread active timestamp.
*/
CHIP_ERROR SetActiveTimestamp(uint64_t aActiveTimestamp);
/**
* Sets the Channel Number in the dataset.
*
* Note that the underlying TLV consists of a 1 byte Channel Page, and a 2 byte Channel Number.
* The Channel Page is always set to zero, as it is currently the only valid value.
*
* @param[in] aChannel The Thread channel.
*
* @retval CHIP_NO_ERROR Successfully set the channel.
* @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread channel.
*/
CHIP_ERROR SetChannel(uint16_t aChannel);
/**
* Sets the Extended PAN ID in the dataset.
*
* @param[in] aExtendedPanId The Thread extended PAN ID.
*
* @retval CHIP_NO_ERROR Successfully set the extended PAN ID.
* @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread extended PAN ID.
*/
CHIP_ERROR SetExtendedPanId(const uint8_t (&aExtendedPanId)[kSizeExtendedPanId]);
/**
* Sets the Master Key in the dataset.
*
* @param[in] aMasterKey The Thread master key.
*
* @retval CHIP_NO_ERROR Successfully set the master key.
* @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread master key.
*/
CHIP_ERROR SetMasterKey(const uint8_t (&aMasterKey)[kSizeMasterKey]);
/**
* Removes the Master Key from the dataset.
*/
void UnsetMasterKey();
/**
* Sets the Mesh Local Prefix in the dataset.
*
* @param[in] aMeshLocalPrefix The Thread mesh local prefix.
*
* @retval CHIP_NO_ERROR Successfully set the Thread mesh local prefix.
* @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread mesh local prefix.
*/
CHIP_ERROR SetMeshLocalPrefix(const uint8_t (&aMeshLocalPrefix)[kSizeMeshLocalPrefix]);
/**
* Sets the Network Name in the dataset. The name must be a non-empty string
* with a maximum length of 16 characters (kSizeNetworkName).
*
* @param[in] aNetworkName The Thread network name.
*
* @retval CHIP_NO_ERROR Successfully set the network name.
* @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread network name.
*/
CHIP_ERROR SetNetworkName(const char * aNetworkName);
/**
* Sets the PAN ID in the dataset.
*
* @param[in] aPanId The Thread PAN ID.
*
* @retval CHIP_NO_ERROR Successfully set the PAN ID.
* @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread PAN ID.
*/
CHIP_ERROR SetPanId(uint16_t aPanId);
/**
* Sets the Pre-Shared Key for the Commissioner (PSKc) in the dataset.
*
* @param[in] aPSKc The Thread PSKc.
*
* @retval CHIP_NO_ERROR Successfully set the PSKc.
* @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread PSKc.
*/
CHIP_ERROR SetPSKc(const uint8_t (&aPSKc)[kSizePSKc]);
/**
* Removes the Pre-Shared Key for the Commissioner (PSKc) from the dataset.
*/
void UnsetPSKc();
/**
* Sets the Channel Mask in the dataset. This value is a non-empty sequence of sub-TLVs as defined in the Thread specification.
*
* @retval CHIP_NO_ERROR on success.
* @retval CHIP_ERROR_NO_MEMORY if there is insufficient space within the dataset.
*/
CHIP_ERROR SetChannelMask(ByteSpan aChannelMask);
/**
* Sets the Security Policy in the dataset.
*
* @retval CHIP_NO_ERROR on success.
* @retval CHIP_ERROR_NO_MEMORY if there is insufficient space within the dataset.
*/
CHIP_ERROR SetSecurityPolicy(uint32_t aSecurityPolicy);
/**
* Sets the Delay Timer value in the dataset.
*
* @retval CHIP_NO_ERROR on success.
* @retval CHIP_ERROR_NO_MEMORY if there is insufficient space within the dataset.
*/
CHIP_ERROR SetDelayTimer(uint32_t aDelayMillis);
/**
* This method clears all data stored in the dataset.
*/
void Clear() { mData = ByteSpan(mBuffer, 0); }
/**
* Returns a ByteSpan view of the current state of the dataset.
* The byte span is only valid as long the OperationalDataset object is alive and not modified.
*/
ByteSpan AsByteSpan() const { return this->OperationalDatasetView::AsByteSpan(); }
private:
uint8_t mBuffer[kSizeOperationalDataset];
void CopyData();
void CopyDataIfNecessary();
void Remove(uint8_t aType);
void Remove(ThreadTLV * aTlv);
ThreadTLV * InsertOrReplace(uint8_t aType, size_t aValueSize);
};
} // namespace Thread
} // namespace chip