[tcat] add tcat implementations and bug fixes (#11402)

Commit adds check if commissioning is possible and if the tcat device is already commissioned.
Adds advertisement update on disconnected and role change.
Fixes key handling for key references.
Fixes the authorization processing.
Implements recent changes of the application TLVs.
This commit is contained in:
arnulfrupp
2025-07-30 12:27:10 -07:00
committed by GitHub
parent 6c55d53a50
commit bb5585d412
28 changed files with 1003 additions and 462 deletions
+8
View File
@@ -244,6 +244,14 @@ otError otPlatBleGapAdvSetData(otInstance *aInstance, uint8_t *aAdvertisementDat
return OT_ERROR_NONE;
}
otError otPlatBleGapAdvUpdateData(otInstance *aInstance, uint8_t *aAdvertisementData, uint16_t aAdvertisementLen)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aAdvertisementData);
OT_UNUSED_VARIABLE(aAdvertisementLen);
return OT_ERROR_NONE;
}
bool otPlatBleSupportsMultiRadio(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
+25 -8
View File
@@ -85,6 +85,10 @@ typedef void (*otHandleBleSecureConnect)(otInstance *aInstance,
/**
* Pointer to call when data was received over a BLE Secure TLS connection.
*
* When TCAT has been started, the TCAT agent automatically responds with status OT_TCAT_STATUS_UNSUPPORTED
* if no response has been generated or no handler is defined. The application may generate a response to
* incoming TCAT application data or vendor-specific data by calling `otBleSecureSendApplicationTlv`.
*/
typedef otHandleTcatApplicationDataReceive otHandleBleSecureReceive;
@@ -409,17 +413,30 @@ otError otBleSecureSendMessage(otInstance *aInstance, otMessage *aMessage);
otError otBleSecureSend(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength);
/**
* Sends a secure BLE data packet containing a TCAT Send Application Data TLV.
* Sends a secure BLE data packet containing application data directed to the application layer @p aApplicationProtocol
* or a response to the latest received application data packet.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV.
* @param[in] aLength A number indicating the length of the data buffer.
* Only a single response can be sent while executing the `otHandleBleSecureReceive` handler. If no (further) response
* is expected `OT_ERROR_REJECTED` is returned.
*
* @retval OT_ERROR_NONE Successfully sent data.
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory.
* @retval OT_ERROR_INVALID_STATE TLS connection was not initialized.
* For responses with a payload @p aApplicationProtocol shall be set to `OT_TCAT_APPLICATION_PROTOCOL_PAYLOAD`.
* For responses with a status @p aApplicationProtocol shall be `OT_TCAT_APPLICATION_PROTOCOL_STATUS` and @ aBuf shall
* contain a single byte `otTcatStatusCode` value.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aApplicationProtocol An application protocol the data is directed to.
* @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV.
* @param[in] aLength A number indicating the length of the data buffer.
*
* @retval OT_ERROR_NONE Successfully sent data.
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory.
* @retval OT_ERROR_INVALID_STATE TLS connection was not initialized.
* @retval OT_ERROR_REJECTED Application protocol is response with data or status but no response is pending.
*/
otError otBleSecureSendApplicationTlv(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength);
otError otBleSecureSendApplicationTlv(otInstance *aInstance,
otTcatApplicationProtocol aApplicationProtocol,
uint8_t *aBuf,
uint16_t aLength);
/**
* Flushes the send buffer.
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (520)
#define OPENTHREAD_API_VERSION (521)
/**
* @addtogroup api-instance
+16
View File
@@ -189,6 +189,22 @@ otError otPlatBleGetAdvertisementBuffer(otInstance *aInstance, uint8_t **aAdvert
*/
otError otPlatBleGapAdvSetData(otInstance *aInstance, uint8_t *aAdvertisementData, uint16_t aAdvertisementLen);
/**
* Updates BLE Advertising data.
*
* @note This function shall be used only for BLE Peripheral role.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aAdvertisementData The formatted TCAT advertisement frame.
* @param[in] aAdvertisementLen The TCAT advertisement frame length.
*
* @retval OT_ERROR_NONE Advertising procedure has been started.
* @retval OT_ERROR_FAILED Update of data failed.
* @retval OT_ERROR_INVALID_ARGS Invalid value has been supplied.
*
*/
otError otPlatBleGapAdvUpdateData(otInstance *aInstance, uint8_t *aAdvertisementData, uint16_t aAdvertisementLen);
/**
* Starts BLE Advertising procedure.
*
+41 -22
View File
@@ -44,6 +44,7 @@
#ifndef OPENTHREAD_TCAT_H_
#define OPENTHREAD_TCAT_H_
#include <stdbool.h>
#include <stdint.h>
#include <openthread/error.h>
@@ -66,8 +67,9 @@ extern "C" {
* @{
*/
#define OT_TCAT_MAX_SERVICE_NAME_LENGTH \
#define OT_TCAT_SERVICE_NAME_MAX_LENGTH \
15 ///< Maximum string length of a UDP or TCP service name (does not include null char).
#define OT_TCAT_APPLICATION_LAYER_MAX_COUNT 4 ///< Maximum number of application layer service names supported
#define OT_TCAT_ADVERTISEMENT_MAX_LEN 29 ///< Maximum length of TCAT advertisement.
#define OT_TCAT_OPCODE 0x2 ///< TCAT Advertisement Operation Code.
@@ -85,9 +87,10 @@ typedef enum otTcatStatusCode
OT_TCAT_STATUS_VALUE_ERROR = 3, ///< The value of the transmitted TLV has an error
OT_TCAT_STATUS_GENERAL_ERROR = 4, ///< An error not matching any other category occurred
OT_TCAT_STATUS_BUSY = 5, ///< Command cannot be executed because the resource is busy
OT_TCAT_STATUS_UNDEFINED = 6, ///< The requested value, data or service is not defined (currently) or not present
OT_TCAT_STATUS_HASH_ERROR = 7, ///< The hash value presented by the commissioner was incorrect
OT_TCAT_STATUS_UNAUTHORIZED = 16, ///< Sender does not have sufficient authorization for the given command
OT_TCAT_STATUS_UNDEFINED = 6, ///< The requested value, data or service is not defined (currently) or not present
OT_TCAT_STATUS_HASH_ERROR = 7, ///< The hash value presented by the commissioner was incorrect
OT_TCAT_STATUS_INVALID_STATE = 8, ///< The TCAT device is not in a correct state for the given command
OT_TCAT_STATUS_UNAUTHORIZED = 16, ///< Sender does not have sufficient authorization for the given command
} otTcatStatusCode;
@@ -96,9 +99,16 @@ typedef enum otTcatStatusCode
*/
typedef enum otTcatApplicationProtocol
{
OT_TCAT_APPLICATION_PROTOCOL_NONE = 0, ///< Message which has been sent without activating the TCAT agent
OT_TCAT_APPLICATION_PROTOCOL_STATUS = 1, ///< Message directed to a UDP service
OT_TCAT_APPLICATION_PROTOCOL_TCP = 2, ///< Message directed to a TCP service
OT_TCAT_APPLICATION_PROTOCOL_NONE = 0, ///< Message which has been sent without activating the TCAT agent
OT_TCAT_APPLICATION_PROTOCOL_STATUS = 0x01, /** Message directed to any application protocol indicating a
response with status value (one byte otTcatStatusCode) */
OT_TCAT_APPLICATION_PROTOCOL_RESPONSE =
0x02, ///< Message directed to any application protocol indicating a response with payload
OT_TCAT_APPLICATION_PROTOCOL_1 = 0x81, ///< Message directed to application protocol 1
OT_TCAT_APPLICATION_PROTOCOL_2 = 0x82, ///< Message directed to application protocol 2
OT_TCAT_APPLICATION_PROTOCOL_3 = 0x83, ///< Message directed to application protocol 3
OT_TCAT_APPLICATION_PROTOCOL_4 = 0x84, ///< Message directed to application protocol 4
OT_TCAT_APPLICATION_PROTOCOL_VENDOR = 0x9F, ///< Message directed to a vendor specific application protocol
} otTcatApplicationProtocol;
@@ -151,35 +161,44 @@ typedef struct otTcatGeneralDeviceId
*/
typedef struct otTcatVendorInfo
{
const char *mProvisioningUrl; ///< Provisioning URL path string
const char *mVendorName; ///< Vendor name string
const char *mVendorModel; ///< Vendor model string
const char *mVendorSwVersion; ///< Vendor software version string
const char *mVendorData; ///< Vendor specific data string
const char *mPskdString; ///< Vendor managed pre-shared key for device
const char *mInstallCode; ///< Vendor managed install code string
const otTcatAdvertisedDeviceId *mAdvertisedDeviceIds; /** Vendor managed advertised device ID array.
Array is terminated like C string with OT_TCAT_DEVICE_ID_EMPTY */
const otTcatGeneralDeviceId *mGeneralDeviceId; /** Vendor managed general device ID array.
(if NULL: device ID is set to EUI-64 in binary format)*/
const char *mProvisioningUrl; ///< Provisioning URL path string
const char *mVendorName; ///< Vendor name string
const char *mVendorModel; ///< Vendor model string
const char *mVendorSwVersion; ///< Vendor software version string
const char *mVendorData; ///< Vendor specific data string
const char *mPskdString; ///< Vendor managed pre-shared key for device
const char *mInstallCode; ///< Vendor managed install code string
const otTcatAdvertisedDeviceId
*mAdvertisedDeviceIds; /** Vendor managed advertised device ID array.
Array is terminated like C string with OT_TCAT_DEVICE_ID_EMPTY */
const otTcatGeneralDeviceId *mGeneralDeviceId; /** Vendor managed general device ID array.
(if NULL: device ID is set to EUI-64 in binary format) */
const char *mApplicationServiceName[OT_TCAT_APPLICATION_LAYER_MAX_COUNT]; /** Array with application service names
as C string with maximum length
OT_TCAT_SERVICE_NAME_MAX_LENGTH or
NULL if not supported */
bool mApplicationServiceIsTcp[OT_TCAT_APPLICATION_LAYER_MAX_COUNT]; /** Array with boolean values indicating
if the service is of TCP type (otherwise
UDP) */
} otTcatVendorInfo;
/**
* Pointer to call when application data was received over a TCAT TLS connection.
* Pointer to call when application data or vendor-specific data was received over a TCAT TLS connection.
* The application may generate a response to an incoming TCAT application data packet. The TCAT agent
* automatically responds with status OT_TCAT_STATUS_UNSUPPORTED if no response has been generated or
* no handler is defined.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMessage A pointer to the message.
* @param[in] aOffset The offset where the application data begins.
* @param[in] aTcatApplicationProtocol The protocol type of the message received.
* @param[in] aServiceName The name of the service the message is direced to.
* @param[in] aTcatApplicationProtocol The application protocol the message is targeted to.
* @param[in] aContext A pointer to arbitrary context information.
*/
typedef void (*otHandleTcatApplicationDataReceive)(otInstance *aInstance,
const otMessage *aMessage,
int32_t aOffset,
otTcatApplicationProtocol aTcatApplicationProtocol,
const char *aServiceName,
void *aContext);
/**
+19
View File
@@ -63,6 +63,25 @@ tcat advid clear
Done
```
### certid
Displays the ID of currently selected TCAT device certificate. A TCAT device supports multiple identities for testing purposes.
```bash
tcat certid
0
Done
```
### certid \<id\>
Selects the ID of the TCAT device certificate. A TCAT device supports multiple identities for testing purposes.
```bash
tcat certid 1
Done
```
### devid
Displays currently set TCAT device id.
+111 -47
View File
@@ -32,7 +32,9 @@
#include "cli/cli_tcat.hpp"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/error.hpp"
#include "common/string.hpp"
#include <openthread/ble_secure.h>
@@ -43,31 +45,60 @@
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
#define CERT_SET_COUNT 2
#define CERT_MAX_SIZE 1024
#define KEY_MAX_SIZE 512
// DeviceCert1 default identity for TCAT certification testing.
// DeviceCert2 extra example.
// WARNING: storage of private keys in code or program memory MUST NOT be used in production.
// The below code is for testing purposes only. For production, secure key storage must be
// used to store private keys.
#define OT_CLI_TCAT_X509_CERT \
"-----BEGIN CERTIFICATE-----\n" \
"MIIB6TCCAZCgAwIBAgICNekwCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk\n" \
"IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ\n" \
"bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT\n" \
"MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU\n" \
"Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDExFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAx\n" \
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE11h/4vKZXVXv+1GDZo066spItloT\n" \
"dpCi0bux0jvpQSHLdQBIc+40zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdqNLMEkw\n" \
"HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC\n" \
"AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIHWu+Rd1\n" \
"VRlzrD8KbuyJcJFTXh2sQ9UIrFIA7+4e/GVcAiAVBdGqTxbt3TGkBBllpafAUB2/\n" \
"s0GJj7E33oblqy5eHQ==\n" \
"-----END CERTIFICATE-----\n"
static const char *const OT_CLI_TCAT_X509_CERT[CERT_SET_COUNT] = {R"(
-----BEGIN CERTIFICATE-----
MIIB6TCCAZCgAwIBAgICNekwCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk
IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ
bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT
MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU
Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDExFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAx
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE11h/4vKZXVXv+1GDZo066spItloT
dpCi0bux0jvpQSHLdQBIc+40zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdqNLMEkw
HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC
AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIHWu+Rd1
VRlzrD8KbuyJcJFTXh2sQ9UIrFIA7+4e/GVcAiAVBdGqTxbt3TGkBBllpafAUB2/
s0GJj7E33oblqy5eHQ==
-----END CERTIFICATE-----
)",
R"(
-----BEGIN CERTIFICATE-----
MIIB6TCCAZCgAwIBAgICNeowCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk
IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ
bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT
MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU
Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDIxFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAy
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE30GMkqSBj3049NtK6G/MRTqcDxpm
i1LxTpSxFIB7P9HVoVM7Cd9X6bBUp5FrSZI+KHtX2HKtXzmzsdJ3gxAmi6NLMEkw
HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC
AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIAbZzVbC
toNYgSWSgxRGzLRo1YJANqRC7yRtJNKTdQ1ZAiAlgGxEW2lkxCAGPUK1m9Wbb4kl
7AhBhYlK6vZz/omTsQ==
-----END CERTIFICATE-----
)"};
#define OT_CLI_TCAT_PRIV_KEY \
"-----BEGIN EC PRIVATE KEY-----\n" \
"MHcCAQEEIIqKM1QTlNaquV74W6Viz/ggXoLqlPOP6LagSyaFO3oUoAoGCCqGSM49\n" \
"AwEHoUQDQgAE11h/4vKZXVXv+1GDZo066spItloTdpCi0bux0jvpQSHLdQBIc+40\n" \
"zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdg==\n" \
"-----END EC PRIVATE KEY-----\n"
static const char *const OT_CLI_TCAT_PRIV_KEY[CERT_SET_COUNT] = {R"(
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIqKM1QTlNaquV74W6Viz/ggXoLqlPOP6LagSyaFO3oUoAoGCCqGSM49
AwEHoUQDQgAE11h/4vKZXVXv+1GDZo066spItloTdpCi0bux0jvpQSHLdQBIc+40
zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdg==
-----END EC PRIVATE KEY-----
)",
R"(
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIP7Al8tJA3QgwD3yIuOSEmJkT3GlWmcHQ59JfhZOjSdUoAoGCCqGSM49
AwEHoUQDQgAE30GMkqSBj3049NtK6G/MRTqcDxpmi1LxTpSxFIB7P9HVoVM7Cd9X
6bBUp5FrSZI+KHtX2HKtXzmzsdJ3gxAmiw==
-----END EC PRIVATE KEY-----
)"};
#define OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE \
"-----BEGIN CERTIFICATE-----\n" \
@@ -86,15 +117,16 @@
"-----END CERTIFICATE-----\n"
namespace ot {
namespace Cli {
otTcatAdvertisedDeviceId sAdvertisedDeviceIds[OT_TCAT_DEVICE_ID_MAX];
otTcatGeneralDeviceId sGeneralDeviceId;
const char kPskdVendor[] = "JJJJJJ";
const char kInstallVendor[] = "InstallCode";
const char kUrl[] = "dummy_url";
const char kPskdVendor[] = "JJJJJJ";
const char kInstallVendor[] = "InstallCode";
const char kUrl[] = "dummy_url";
const char kApplicationServiceName1[] = "echo";
const char kApplicationServiceName2[] = "discard";
static bool IsDeviceIdSet(void)
{
@@ -114,28 +146,24 @@ static void HandleBleSecureReceive(otInstance *aInstance,
const otMessage *aMessage,
int32_t aOffset,
otTcatApplicationProtocol aTcatApplicationProtocol,
const char *aServiceName,
void *aContext)
{
OT_UNUSED_VARIABLE(aContext);
OT_UNUSED_VARIABLE(aTcatApplicationProtocol);
OT_UNUSED_VARIABLE(aServiceName);
static constexpr int kTextMaxLen = 100;
static constexpr uint8_t kBufPrefixLen = 5;
static constexpr int kTextMaxLen = 100;
uint16_t nLen;
uint8_t buf[kTextMaxLen];
nLen =
otMessageRead(aMessage, static_cast<uint16_t>(aOffset), buf + kBufPrefixLen, sizeof(buf) - kBufPrefixLen - 1);
memcpy(buf, "RECV:", kBufPrefixLen);
buf[nLen + kBufPrefixLen] = 0;
IgnoreReturnValue(otBleSecureSendApplicationTlv(aInstance, buf, (uint16_t)strlen((char *)buf)));
IgnoreReturnValue(otBleSecureFlush(aInstance));
if (aTcatApplicationProtocol == OT_TCAT_APPLICATION_PROTOCOL_1 ||
aTcatApplicationProtocol == OT_TCAT_APPLICATION_PROTOCOL_VENDOR)
{
uint8_t buf[kTextMaxLen];
uint16_t nLen = otMessageRead(aMessage, static_cast<uint16_t>(aOffset), buf, sizeof(buf));
IgnoreReturnValue(otBleSecureSendApplicationTlv(aInstance, OT_TCAT_APPLICATION_PROTOCOL_RESPONSE, buf, nLen));
}
else if (aTcatApplicationProtocol == OT_TCAT_APPLICATION_PROTOCOL_2)
{
uint8_t status = OT_TCAT_STATUS_SUCCESS;
IgnoreReturnValue(otBleSecureSendApplicationTlv(aInstance, OT_TCAT_APPLICATION_PROTOCOL_STATUS, &status, 1));
}
}
/**
@@ -230,6 +258,38 @@ exit:
return error;
}
/**
* @cli tcat certid
* @code
* tcat devid certid 0
* Done
* @endcode
* @cparam tcat certid [@ca{value}]
* * The `value` int value of the ID.
* @par
* Selects a predefined certificate.
*/
template <> otError Tcat::Process<Cmd("certid")>(Arg aArgs[])
{
Error error = kErrorNone;
uint8_t certCandidate = 0;
if (aArgs[0].IsEmpty())
{
OutputLine("%d", mSelectedCert);
ExitNow();
}
SuccessOrExit(error = aArgs[0].ParseAsUint8(certCandidate));
VerifyOrExit(certCandidate < CERT_SET_COUNT, error = kErrorInvalidArgs);
mSelectedCert = certCandidate;
exit:
return error;
}
/**
* @cli tcat devid
* @code
@@ -292,9 +352,12 @@ template <> otError Tcat::Process<Cmd("start")>(Arg aArgs[])
otError error = OT_ERROR_NONE;
ClearAllBytes(mVendorInfo);
mVendorInfo.mPskdString = kPskdVendor;
mVendorInfo.mProvisioningUrl = kUrl;
mVendorInfo.mInstallCode = kInstallVendor;
mVendorInfo.mPskdString = kPskdVendor;
mVendorInfo.mProvisioningUrl = kUrl;
mVendorInfo.mInstallCode = kInstallVendor;
mVendorInfo.mApplicationServiceName[0] = kApplicationServiceName1;
mVendorInfo.mApplicationServiceName[1] = kApplicationServiceName2;
mVendorInfo.mApplicationServiceIsTcp[1] = true;
if (IsDeviceIdSet())
{
@@ -306,9 +369,10 @@ template <> otError Tcat::Process<Cmd("start")>(Arg aArgs[])
mVendorInfo.mGeneralDeviceId = &sGeneralDeviceId;
}
otBleSecureSetCertificate(GetInstancePtr(), reinterpret_cast<const uint8_t *>(OT_CLI_TCAT_X509_CERT),
sizeof(OT_CLI_TCAT_X509_CERT), reinterpret_cast<const uint8_t *>(OT_CLI_TCAT_PRIV_KEY),
sizeof(OT_CLI_TCAT_PRIV_KEY));
otBleSecureSetCertificate(GetInstancePtr(), reinterpret_cast<const uint8_t *>(OT_CLI_TCAT_X509_CERT[mSelectedCert]),
StringLength(OT_CLI_TCAT_X509_CERT[mSelectedCert], CERT_MAX_SIZE) + 1,
reinterpret_cast<const uint8_t *>(OT_CLI_TCAT_PRIV_KEY[mSelectedCert]),
StringLength(OT_CLI_TCAT_PRIV_KEY[mSelectedCert], KEY_MAX_SIZE) + 1);
otBleSecureSetCaCertificateChain(GetInstancePtr(),
reinterpret_cast<const uint8_t *>(OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE),
+2
View File
@@ -55,6 +55,7 @@ public:
*/
Tcat(otInstance *aInstance, OutputImplementer &aOutputImplementer)
: Utils(aInstance, aOutputImplementer)
, mSelectedCert(0)
{
}
@@ -77,6 +78,7 @@ private:
template <CommandId kCommandId> otError Process(Arg aArgs[]);
otTcatVendorInfo mVendorInfo;
uint8_t mSelectedCert;
};
} // namespace Cli
+5 -2
View File
@@ -195,9 +195,12 @@ otError otBleSecureSend(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength)
return AsCoreType(aInstance).Get<Ble::BleSecure>().Send(aBuf, aLength);
}
otError otBleSecureSendApplicationTlv(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength)
otError otBleSecureSendApplicationTlv(otInstance *aInstance,
otTcatApplicationProtocol aApplicationProtocol,
uint8_t *aBuf,
uint16_t aLength)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().SendApplicationTlv(aBuf, aLength);
return AsCoreType(aInstance).Get<Ble::BleSecure>().SendApplicationTlv(MapEnum(aApplicationProtocol), aBuf, aLength);
}
otError otBleSecureFlush(otInstance *aInstance) { return AsCoreType(aInstance).Get<Ble::BleSecure>().Flush(); }
+334 -256
View File
@@ -33,6 +33,8 @@
#include "tcat_agent.hpp"
#include "common/code_utils.hpp"
#include "common/error.hpp"
#include "crypto/storage.hpp"
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
@@ -56,7 +58,6 @@ bool TcatAgent::VendorInfo::IsValid(void) const
TcatAgent::TcatAgent(Instance &aInstance)
: InstanceLocator(aInstance)
, mVendorInfo(nullptr)
, mCurrentApplicationProtocol(kApplicationProtocolNone)
, mState(kStateDisabled)
, mCommissionerHasNetworkName(false)
, mCommissionerHasDomainName(false)
@@ -65,9 +66,10 @@ TcatAgent::TcatAgent(Instance &aInstance)
, mPskdVerified(false)
, mPskcVerified(false)
, mInstallCodeVerified(false)
, mIsCommissioned(false)
, mApplicationResponsePending(false)
{
mJoinerPskd.Clear();
mCurrentServiceName[0] = 0;
}
Error TcatAgent::Start(AppDataReceiveCallback aAppDataReceiveCallback, JoinCallback aHandler, void *aContext)
@@ -79,9 +81,7 @@ Error TcatAgent::Start(AppDataReceiveCallback aAppDataReceiveCallback, JoinCallb
mAppDataReceiveCallback.Set(aAppDataReceiveCallback, aContext);
mJoinCallback.Set(aHandler, aContext);
mRandomChallenge = 0;
mCurrentApplicationProtocol = kApplicationProtocolNone;
mState = kStateEnabled;
mState = kStateEnabled;
exit:
LogWarnOnError(error, "start TCAT agent");
@@ -90,14 +90,19 @@ exit:
void TcatAgent::Stop(void)
{
mCurrentApplicationProtocol = kApplicationProtocolNone;
mState = kStateDisabled;
mState = kStateDisabled;
mAppDataReceiveCallback.Clear();
mJoinCallback.Clear();
mRandomChallenge = 0;
mPskdVerified = false;
mPskcVerified = false;
mInstallCodeVerified = false;
mCommissionerHasNetworkName = false;
mCommissionerHasDomainName = false;
mCommissionerHasExtendedPanId = false;
mCommissionerNetworkName.m8[0] = '\0';
mCommissionerDomainName.m8[0] = '\0';
mRandomChallenge = 0;
mPskdVerified = false;
mPskcVerified = false;
mInstallCodeVerified = false;
mIsCommissioned = false;
LogInfo("TCAT agent stopped");
}
@@ -162,9 +167,8 @@ Error TcatAgent::Connected(MeshCoP::Tls::Extension &aTls)
}
}
mCurrentApplicationProtocol = kApplicationProtocolNone;
mCurrentServiceName[0] = 0;
mState = kStateConnected;
mState = kStateConnected;
mIsCommissioned = Get<ActiveDatasetManager>().IsCommissioned();
LogInfo("TCAT agent connected");
exit:
@@ -173,8 +177,6 @@ exit:
void TcatAgent::Disconnected(void)
{
mCurrentApplicationProtocol = kApplicationProtocolNone;
if (mState != kStateDisabled)
{
mState = kStateEnabled;
@@ -188,99 +190,113 @@ void TcatAgent::Disconnected(void)
LogInfo("TCAT agent disconnected");
}
uint8_t TcatAgent::CheckAuthorizationRequirements(CommandClassFlags aFlagsRequired, Dataset::Info *aDatasetInfo) const
{
uint8_t res = kAccessFlag;
for (uint16_t flag = kPskdFlag; flag < kMaxFlag; flag <<= 1)
{
if (aFlagsRequired & flag)
{
switch (flag)
{
case kPskdFlag:
if (mPskdVerified)
{
res |= flag;
}
break;
case kNetworkNameFlag:
if (aDatasetInfo != nullptr && mCommissionerHasNetworkName &&
aDatasetInfo->IsPresent<Dataset::kNetworkName>() &&
(aDatasetInfo->Get<Dataset::kNetworkName>() == mCommissionerNetworkName))
{
res |= flag;
}
break;
case kExtendedPanIdFlag:
if (aDatasetInfo != nullptr && mCommissionerHasExtendedPanId &&
aDatasetInfo->IsPresent<Dataset::kExtendedPanId>() &&
(aDatasetInfo->Get<Dataset::kExtendedPanId>() == mCommissionerExtendedPanId))
{
res |= flag;
}
break;
case kThreadDomainFlag:
if (mCommissionerHasDomainName)
{
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4)
if (Get<MeshCoP::NetworkNameManager>().GetDomainName() == mCommissionerDomainName)
#else
if (StringMatch(mCommissionerDomainName.GetAsCString(), NetworkName::kDomainNameInit))
#endif
{
res |= flag;
}
}
break;
case kPskcFlag:
if (mPskcVerified)
{
res |= flag;
}
break;
default:
LogCrit("Error while processing access flags. Unexpected flag %d", flag);
OT_ASSERT(false); // Should not get here
}
}
}
return res;
}
bool TcatAgent::CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags,
CommandClassFlags aDeviceCommandClassFlags,
Dataset *aDataset) const
{
bool authorized = false;
bool additionalDeviceRequirementMet = false;
bool domainNamesMatch = false;
bool networkNamesMatch = false;
bool extendedPanIdsMatch = false;
bool authorized = false;
uint8_t deviceRequirementMet;
uint8_t commissionerRequirementMet;
Dataset::Info datasetInfo;
Error datasetError = kErrorNone;
VerifyOrExit(IsConnected());
VerifyOrExit(aCommissionerCommandClassFlags & kAccessFlag);
if (aDeviceCommandClassFlags & kAccessFlag)
if (aDataset == nullptr)
{
additionalDeviceRequirementMet = true;
datasetError = Get<ActiveDatasetManager>().Read(datasetInfo);
}
else
{
aDataset->ConvertTo(datasetInfo);
}
if (!additionalDeviceRequirementMet && (aDeviceCommandClassFlags & kPskdFlag))
if (datasetError == kErrorNone)
{
additionalDeviceRequirementMet = mPskdVerified;
deviceRequirementMet = CheckAuthorizationRequirements(aDeviceCommandClassFlags, &datasetInfo);
commissionerRequirementMet = CheckAuthorizationRequirements(aCommissionerCommandClassFlags, &datasetInfo);
}
else
{
deviceRequirementMet = CheckAuthorizationRequirements(aDeviceCommandClassFlags, nullptr);
commissionerRequirementMet = CheckAuthorizationRequirements(aCommissionerCommandClassFlags, nullptr);
}
if (!additionalDeviceRequirementMet && (aDeviceCommandClassFlags & kPskcFlag))
if (aDataset != nullptr) // For set active operational dataset TLV the PSKc check is always successful
{
additionalDeviceRequirementMet = mPskcVerified;
deviceRequirementMet |= kPskcFlag;
commissionerRequirementMet |= (aCommissionerCommandClassFlags & kPskcFlag);
}
if (mCommissionerHasNetworkName || mCommissionerHasExtendedPanId)
{
Dataset::Info datasetInfo;
Error datasetError = kErrorNone;
if (aDataset == nullptr)
{
datasetError = Get<ActiveDatasetManager>().Read(datasetInfo);
}
else
{
aDataset->ConvertTo(datasetInfo);
}
if (datasetError == kErrorNone)
{
if (datasetInfo.IsPresent<Dataset::kNetworkName>() && mCommissionerHasNetworkName &&
(datasetInfo.Get<Dataset::kNetworkName>() == mCommissionerNetworkName))
{
networkNamesMatch = true;
}
if (datasetInfo.IsPresent<Dataset::kExtendedPanId>() && mCommissionerHasExtendedPanId &&
(datasetInfo.Get<Dataset::kExtendedPanId>() == mCommissionerExtendedPanId))
{
extendedPanIdsMatch = true;
}
}
}
if (!networkNamesMatch)
{
VerifyOrExit((aCommissionerCommandClassFlags & kNetworkNameFlag) == 0);
}
else if (aDeviceCommandClassFlags & kNetworkNameFlag)
{
additionalDeviceRequirementMet = true;
}
if (!extendedPanIdsMatch)
{
VerifyOrExit((aCommissionerCommandClassFlags & kExtendedPanIdFlag) == 0);
}
else if (aDeviceCommandClassFlags & kExtendedPanIdFlag)
{
additionalDeviceRequirementMet = true;
}
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
VerifyOrExit((aCommissionerCommandClassFlags & kThreadDomainFlag) == 0);
#endif
if (!domainNamesMatch)
{
VerifyOrExit((aCommissionerCommandClassFlags & kThreadDomainFlag) == 0);
}
else if (aDeviceCommandClassFlags & kThreadDomainFlag)
{
additionalDeviceRequirementMet = true;
}
if (additionalDeviceRequirementMet)
{
authorized = true;
}
authorized = (commissionerRequirementMet == aCommissionerCommandClassFlags) &&
(deviceRequirementMet & aDeviceCommandClassFlags);
exit:
return authorized;
@@ -306,7 +322,7 @@ bool TcatAgent::IsCommandClassAuthorized(CommandClass aCommandClass) const
mDeviceAuthorizationField.mExtractionFlags, nullptr);
break;
case kTlvDecommissioning:
case kDecommissioning:
authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mDecommissioningFlags,
mDeviceAuthorizationField.mDecommissioningFlags, nullptr);
break;
@@ -324,46 +340,6 @@ bool TcatAgent::IsCommandClassAuthorized(CommandClass aCommandClass) const
return authorized;
}
TcatAgent::CommandClass TcatAgent::GetCommandClass(uint8_t aTlvType) const
{
static constexpr int kGeneralTlvs = 0x1F;
static constexpr int kCommissioningTlvs = 0x3F;
static constexpr int kExtractionTlvs = 0x5F;
static constexpr int kTlvDecommissioningTlvs = 0x7F;
static constexpr int kApplicationTlvs = 0x9F;
if (aTlvType <= kGeneralTlvs)
{
return kGeneral;
}
else if (aTlvType <= kCommissioningTlvs)
{
return kCommissioning;
}
else if (aTlvType <= kExtractionTlvs)
{
return kExtraction;
}
else if (aTlvType <= kTlvDecommissioningTlvs)
{
return kTlvDecommissioning;
}
else if (aTlvType <= kApplicationTlvs)
{
return kApplication;
}
else
{
return kInvalid;
}
}
bool TcatAgent::CanProcessTlv(uint8_t aTlvType) const
{
CommandClass tlvCommandClass = GetCommandClass(aTlvType);
return IsCommandClassAuthorized(tlvCommandClass);
}
Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutgoingMessage)
{
Error error = kErrorParse;
@@ -388,88 +364,98 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutg
offset += sizeof(ot::Tlv);
}
if (!CanProcessTlv(tlv.GetType()))
switch (tlv.GetType())
{
error = kErrorRejected;
case kTlvDisconnect:
error = kErrorAbort;
response = true; // true - to avoid response-with-status being sent.
break;
case kTlvSetActiveOperationalDataset:
error = HandleSetActiveOperationalDataset(aIncomingMessage, offset, length);
break;
case kTlvGetActiveOperationalDataset:
error = HandleGetActiveOperationalDataset(aOutgoingMessage, response);
break;
case kTlvGetDiagnosticTlvs:
error = HandleGetDiagnosticTlvs(aIncomingMessage, aOutgoingMessage, offset, length, response);
break;
case kTlvStartThreadInterface:
error = HandleStartThreadInterface();
break;
case kTlvStopThreadInterface:
error = HandleStopThreadInterface();
break;
case kTlvGetApplicationLayers:
error = HandleGetApplicationLayers(aOutgoingMessage, response);
break;
case kTlvSendApplicationData1:
case kTlvSendApplicationData2:
case kTlvSendApplicationData3:
case kTlvSendApplicationData4:
case kTlvSendVendorSpecificData:
error = HandleApplicationData(aIncomingMessage, offset, static_cast<TcatApplicationProtocol>(tlv.GetType()),
response);
break;
case kTlvDecommission:
error = HandleDecomission();
break;
case kTlvPing:
error = HandlePing(aIncomingMessage, aOutgoingMessage, offset, length, response);
break;
case kTlvGetNetworkName:
error = HandleGetNetworkName(aOutgoingMessage, response);
break;
case kTlvGetDeviceId:
error = HandleGetDeviceId(aOutgoingMessage, response);
break;
case kTlvGetExtendedPanID:
error = HandleGetExtPanId(aOutgoingMessage, response);
break;
case kTlvGetProvisioningURL:
error = HandleGetProvisioningUrl(aOutgoingMessage, response);
break;
case kTlvPresentPskdHash:
error = HandlePresentPskdHash(aIncomingMessage, offset, length);
break;
case kTlvPresentPskcHash:
error = HandlePresentPskcHash(aIncomingMessage, offset, length);
break;
case kTlvPresentInstallCodeHash:
error = HandlePresentInstallCodeHash(aIncomingMessage, offset, length);
break;
case kTlvRequestRandomNumChallenge:
error = HandleRequestRandomNumberChallenge(aOutgoingMessage, response);
break;
case kTlvRequestPskdHash:
error = HandleRequestPskdHash(aIncomingMessage, aOutgoingMessage, offset, length, response);
break;
case kTlvGetCommissionerCertificate:
error = HandleGetCommissionerCertificate(aOutgoingMessage, response);
break;
default:
error = kErrorInvalidCommand;
}
else
{
switch (tlv.GetType())
{
case kTlvDisconnect:
error = kErrorAbort;
response = true; // true - to avoid response-with-status being sent.
break;
case kTlvSetActiveOperationalDataset:
error = HandleSetActiveOperationalDataset(aIncomingMessage, offset, length);
break;
case kTlvGetActiveOperationalDataset:
error = HandleGetActiveOperationalDataset(aOutgoingMessage, response);
break;
case kTlvGetDiagnosticTlvs:
error = HandleGetDiagnosticTlvs(aIncomingMessage, aOutgoingMessage, offset, length, response);
break;
case kTlvStartThreadInterface:
error = HandleStartThreadInterface();
break;
case kTlvStopThreadInterface:
error = otThreadSetEnabled(&GetInstance(), false);
break;
case kTlvSendApplicationData:
LogInfo("Application data len:%d, offset:%d", length, offset);
mAppDataReceiveCallback.InvokeIfSet(&GetInstance(), &aIncomingMessage, offset,
MapEnum(mCurrentApplicationProtocol), mCurrentServiceName);
response = true;
error = kErrorNone;
break;
case kTlvDecommission:
error = HandleDecomission();
break;
case kTlvPing:
error = HandlePing(aIncomingMessage, aOutgoingMessage, offset, length, response);
break;
case kTlvGetNetworkName:
error = HandleGetNetworkName(aOutgoingMessage, response);
break;
case kTlvGetDeviceId:
error = HandleGetDeviceId(aOutgoingMessage, response);
break;
case kTlvGetExtendedPanID:
error = HandleGetExtPanId(aOutgoingMessage, response);
break;
case kTlvGetProvisioningURL:
error = HandleGetProvisioningUrl(aOutgoingMessage, response);
break;
case kTlvPresentPskdHash:
error = HandlePresentPskdHash(aIncomingMessage, offset, length);
break;
case kTlvPresentPskcHash:
error = HandlePresentPskcHash(aIncomingMessage, offset, length);
break;
case kTlvPresentInstallCodeHash:
error = HandlePresentInstallCodeHash(aIncomingMessage, offset, length);
break;
case kTlvRequestRandomNumChallenge:
error = HandleRequestRandomNumberChallenge(aOutgoingMessage, response);
break;
case kTlvRequestPskdHash:
error = HandleRequestPskdHash(aIncomingMessage, aOutgoingMessage, offset, length, response);
break;
case kTlvGetCommissionerCertificate:
error = HandleGetCommissionerCertificate(aOutgoingMessage, response);
break;
default:
error = kErrorInvalidCommand;
}
}
if (!response)
{
StatusCode statusCode;
@@ -480,30 +466,40 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutg
statusCode = kStatusSuccess;
break;
case kErrorInvalidState:
statusCode = kStatusUndefined;
case kErrorNotImplemented:
case kErrorInvalidCommand:
statusCode = kStatusUnsupported;
break;
case kErrorParse:
statusCode = kStatusParseError;
break;
case kErrorInvalidCommand:
statusCode = kStatusUnsupported;
case kErrorInvalidArgs:
statusCode = kStatusValueError;
break;
case kErrorRejected:
statusCode = kStatusUnauthorized;
case kErrorBusy:
statusCode = kStatusBusy;
break;
case kErrorNotImplemented:
statusCode = kStatusUnsupported;
case kErrorNotFound:
statusCode = kStatusUndefined;
break;
case kErrorSecurity:
statusCode = kStatusHashError;
break;
case kErrorInvalidState:
case kErrorAlready:
statusCode = kStatusInvalidState;
break;
case kErrorRejected:
statusCode = kStatusUnauthorized;
break;
default:
statusCode = kStatusGeneralError;
break;
@@ -524,9 +520,12 @@ Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncomingMessa
uint8_t buf[kCommissionerCertMaxLength];
size_t bufLen = sizeof(buf);
VerifyOrExit(!mIsCommissioned, error = kErrorAlready);
offsetRange.Init(aOffset, aLength);
SuccessOrExit(error = dataset.SetFrom(aIncomingMessage, offsetRange));
SuccessOrExit(error = dataset.ValidateTlvs());
VerifyOrExit(dataset.ContainsTlv(Tlv::kNetworkKey), error = kErrorInvalidArgs);
if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mCommissioningFlags,
mDeviceAuthorizationField.mCommissioningFlags, &dataset))
@@ -550,13 +549,7 @@ Error TcatAgent::HandleGetActiveOperationalDataset(Message &aOutgoingMessage, bo
Dataset dataset;
Dataset::Tlvs datasetTlvs;
if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mCommissioningFlags,
mDeviceAuthorizationField.mCommissioningFlags, &dataset))
{
error = kErrorRejected;
ExitNow();
}
VerifyOrExit(IsCommandClassAuthorized(kExtraction), error = kErrorRejected);
SuccessOrExit(error = Get<ActiveDatasetManager>().Read(datasetTlvs));
SuccessOrExit(
error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, datasetTlvs.mTlvs, datasetTlvs.mLength));
@@ -568,20 +561,12 @@ exit:
Error TcatAgent::HandleGetCommissionerCertificate(Message &aOutgoingMessage, bool &aResponse)
{
Error error = kErrorNone;
Dataset dataset;
uint8_t buf[kCommissionerCertMaxLength];
uint16_t bufLen = sizeof(buf);
Error error = kErrorNone;
unsigned char buf[kCommissionerCertMaxLength];
uint16_t bufLen = sizeof(buf);
if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mCommissioningFlags,
mDeviceAuthorizationField.mCommissioningFlags, &dataset))
{
error = kErrorRejected;
ExitNow();
}
VerifyOrExit(kErrorNone == Get<Settings>().ReadTcatCommissionerCertificate(buf, bufLen),
error = kErrorInvalidState);
VerifyOrExit(IsCommandClassAuthorized(kCommissioning), error = kErrorRejected);
VerifyOrExit(kErrorNone == Get<Settings>().ReadTcatCommissionerCertificate(buf, bufLen), error = kErrorNotFound);
SuccessOrExit(error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, buf, bufLen));
aResponse = true;
@@ -653,15 +638,8 @@ Error TcatAgent::HandleDecomission(void)
Error error = kErrorNone;
unsigned char buf[kCommissionerCertMaxLength];
size_t bufLen = sizeof(buf);
Dataset dataset;
if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mDecommissioningFlags,
mDeviceAuthorizationField.mDecommissioningFlags, &dataset))
{
error = kErrorRejected;
ExitNow();
}
VerifyOrExit(IsCommandClassAuthorized(kDecommissioning), error = kErrorRejected);
SuccessOrExit(error = Get<Ble::BleSecure>().GetPeerCertificateDer(buf, &bufLen, bufLen));
Get<Settings>().SaveTcatCommissionerCertificate(buf, static_cast<uint16_t>(bufLen));
@@ -719,9 +697,9 @@ Error TcatAgent::HandleGetNetworkName(Message &aOutgoingMessage, bool &aResponse
Error error = kErrorNone;
MeshCoP::NameData nameData = Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsData();
VerifyOrExit(Get<ActiveDatasetManager>().IsCommissioned(), error = kErrorInvalidState);
VerifyOrExit(Get<ActiveDatasetManager>().IsCommissioned(), error = kErrorNotFound);
#if !OPENTHREAD_CONFIG_ALLOW_EMPTY_NETWORK_NAME
VerifyOrExit(nameData.GetLength() > 0, error = kErrorInvalidState);
VerifyOrExit(nameData.GetLength() > 0, error = kErrorNotFound);
#endif
SuccessOrExit(
@@ -739,6 +717,8 @@ Error TcatAgent::HandleGetDeviceId(Message &aOutgoingMessage, bool &aResponse)
Mac::ExtAddress eui64;
Error error = kErrorNone;
VerifyOrExit(mVendorInfo != nullptr, error = kErrorInvalidState);
if (mVendorInfo->mGeneralDeviceId != nullptr)
{
length = mVendorInfo->mGeneralDeviceId->mDeviceIdLen;
@@ -765,7 +745,7 @@ Error TcatAgent::HandleGetExtPanId(Message &aOutgoingMessage, bool &aResponse)
{
Error error;
VerifyOrExit(Get<ActiveDatasetManager>().IsCommissioned(), error = kErrorInvalidState);
VerifyOrExit(Get<ActiveDatasetManager>().IsCommissioned(), error = kErrorNotFound);
SuccessOrExit(error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload,
&Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId(), sizeof(ExtendedPanId)));
@@ -780,10 +760,11 @@ Error TcatAgent::HandleGetProvisioningUrl(Message &aOutgoingMessage, bool &aResp
Error error = kErrorNone;
uint16_t length;
VerifyOrExit(mVendorInfo != nullptr, error = kErrorInvalidState);
VerifyOrExit(mVendorInfo->mProvisioningUrl != nullptr, error = kErrorInvalidState);
length = StringLength(mVendorInfo->mProvisioningUrl, kProvisioningUrlMaxLength);
VerifyOrExit(length > 0 && length <= Tlv::kBaseTlvMaxLength, error = kErrorInvalidState);
VerifyOrExit(length > 0 && length <= Tlv::kBaseTlvMaxLength, error = kErrorNotFound);
SuccessOrExit(error =
Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, mVendorInfo->mProvisioningUrl, length));
@@ -797,6 +778,7 @@ Error TcatAgent::HandlePresentPskdHash(const Message &aIncomingMessage, uint16_t
{
Error error = kErrorNone;
VerifyOrExit(mVendorInfo != nullptr, error = kErrorInvalidState);
VerifyOrExit(mVendorInfo->mPskdString != nullptr, error = kErrorSecurity);
SuccessOrExit(error = VerifyHash(aIncomingMessage, aOffset, aLength, mVendorInfo->mPskdString,
@@ -828,6 +810,7 @@ Error TcatAgent::HandlePresentInstallCodeHash(const Message &aIncomingMessage, u
{
Error error = kErrorNone;
VerifyOrExit(mVendorInfo != nullptr, error = kErrorInvalidState);
VerifyOrExit(mVendorInfo->mInstallCode != nullptr, error = kErrorSecurity);
SuccessOrExit(error = VerifyHash(aIncomingMessage, aOffset, aLength, mVendorInfo->mInstallCode,
@@ -861,6 +844,7 @@ Error TcatAgent::HandleRequestPskdHash(const Message &aIncomingMessage,
uint64_t providedChallenge = 0;
Crypto::HmacSha256::Hash hash;
VerifyOrExit(mVendorInfo != nullptr, error = kErrorInvalidState);
VerifyOrExit(StringLength(mVendorInfo->mPskdString, kMaxPskdLength) != 0, error = kErrorFailed);
VerifyOrExit(aLength == sizeof(providedChallenge), error = kErrorParse);
@@ -903,12 +887,91 @@ void TcatAgent::CalculateHash(uint64_t aChallenge, const char *aBuf, size_t aBuf
Crypto::Key cryptoKey;
Crypto::HmacSha256 hmac;
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
Crypto::Storage::KeyRef keyRef;
SuccessOrExit(Crypto::Storage::ImportKey(keyRef, Crypto::Storage::kKeyTypeHmac,
Crypto::Storage::kKeyAlgorithmHmacSha256, Crypto::Storage::kUsageSignHash,
Crypto::Storage::kTypeVolatile, reinterpret_cast<const uint8_t *>(aBuf),
aBufLen));
cryptoKey.SetAsKeyRef(keyRef);
#else
cryptoKey.Set(reinterpret_cast<const uint8_t *>(aBuf), static_cast<uint16_t>(aBufLen));
#endif
hmac.Start(cryptoKey);
hmac.Update(aChallenge);
hmac.Update(rawKey.p, static_cast<uint16_t>(rawKey.len));
hmac.Finish(aHash);
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
Crypto::Storage::DestroyKey(keyRef);
exit:
#endif
return;
}
Error TcatAgent::HandleGetApplicationLayers(Message &aOutgoingMessage, bool &aResponse)
{
Error error = kErrorNone;
ot::Tlv tlv;
uint8_t replyLen = 0;
uint8_t count = 0;
static_assert((kApplicationLayerMaxCount * (kServiceNameMaxLength + 2)) <= 250,
"Unsupported TCAT application layers configuration");
VerifyOrExit(mVendorInfo != nullptr, error = kErrorInvalidState);
VerifyOrExit(IsCommandClassAuthorized(kApplication), error = kErrorRejected);
for (uint8_t i = 0; i < kApplicationLayerMaxCount && mVendorInfo->mApplicationServiceName[i] != nullptr; i++)
{
replyLen += sizeof(tlv);
replyLen += StringLength(mVendorInfo->mApplicationServiceName[i], kServiceNameMaxLength);
count++;
}
tlv.SetType(kTlvResponseWithPayload);
tlv.SetLength(replyLen);
SuccessOrExit(error = aOutgoingMessage.Append(tlv));
for (uint8_t i = 0; i < count; i++)
{
uint16_t length = StringLength(mVendorInfo->mApplicationServiceName[i], kServiceNameMaxLength);
uint8_t type = mVendorInfo->mApplicationServiceIsTcp[i] ? kTlvServiceNameTcp : kTlvServiceNameUdp;
SuccessOrExit(error = Tlv::AppendTlv(aOutgoingMessage, type, mVendorInfo->mApplicationServiceName[i], length));
}
aResponse = true;
exit:
return error;
}
Error TcatAgent::HandleApplicationData(const Message &aIncomingMessage,
uint16_t aOffset,
TcatApplicationProtocol aApplicationProtocol,
bool &aResponse)
{
Error error = kErrorNone;
VerifyOrExit(IsCommandClassAuthorized(kApplication), error = kErrorRejected);
mApplicationResponsePending = true;
mAppDataReceiveCallback.InvokeIfSet(&GetInstance(), &aIncomingMessage, aOffset,
static_cast<otTcatApplicationProtocol>(aApplicationProtocol));
if (mApplicationResponsePending)
{
mApplicationResponsePending = false;
error = kErrorNotImplemented; // Application unsupported
}
else
{
aResponse = true;
}
exit:
return error;
}
Error TcatAgent::HandleStartThreadInterface(void)
@@ -916,6 +979,7 @@ Error TcatAgent::HandleStartThreadInterface(void)
Error error;
Dataset::Info datasetInfo;
VerifyOrExit(IsCommandClassAuthorized(kCommissioning), error = kErrorRejected);
VerifyOrExit(Get<ActiveDatasetManager>().Read(datasetInfo) == kErrorNone, error = kErrorInvalidState);
VerifyOrExit(datasetInfo.IsPresent<Dataset::kNetworkKey>(), error = kErrorInvalidState);
@@ -930,6 +994,18 @@ exit:
return error;
}
Error TcatAgent::HandleStopThreadInterface(void)
{
Error error;
VerifyOrExit(IsCommandClassAuthorized(kCommissioning), error = kErrorRejected);
error = otThreadSetEnabled(&GetInstance(), false);
exit:
return error;
}
void SeralizeTcatAdvertisementTlv(uint8_t *aBuffer,
uint16_t &aOffset,
TcatAdvertisementTlvType aType,
@@ -996,9 +1072,11 @@ Error TcatAgent::GetAdvertisementData(uint16_t &aLen, uint8_t *aAdvertisementDat
reinterpret_cast<uint8_t *>(&caps));
}
tas.mRsv = 0;
tas.mMultiradioSupport = otPlatBleSupportsMultiRadio(&GetInstance());
tas.mIsCommisionned = Get<ActiveDatasetManager>().IsCommissioned();
tas.mRsv = 0;
tas.mMultiRadioSupport = otPlatBleSupportsMultiRadio(&GetInstance());
tas.mStoresActiveOperationalDataset =
Get<ActiveDatasetManager>().IsPartiallyComplete() || Get<ActiveDatasetManager>().IsCommissioned();
tas.mIsCommissioned = Get<ActiveDatasetManager>().IsCommissioned();
tas.mThreadNetworkActive = Get<Mle::Mle>().IsAttached();
tas.mDeviceType = Get<Mle::Mle>().GetDeviceMode().IsFullThreadDevice();
tas.mRxOnWhenIdle = Get<Mle::Mle>().GetDeviceMode().IsRxOnWhenIdle();
+72 -50
View File
@@ -83,11 +83,11 @@ public:
*/
enum CommandClass
{
kGeneral = OT_TCAT_COMMAND_CLASS_GENERAL, ///< TCAT commands related to general operations
kCommissioning = OT_TCAT_COMMAND_CLASS_COMMISSIONING, ///< TCAT commands related to commissioning
kExtraction = OT_TCAT_COMMAND_CLASS_EXTRACTION, ///< TCAT commands related to key extraction
kTlvDecommissioning = OT_TCAT_COMMAND_CLASS_DECOMMISSIONING, ///< TCAT commands related to de-commissioning
kApplication = OT_TCAT_COMMAND_CLASS_APPLICATION, ///< TCAT commands related to application layer
kGeneral = OT_TCAT_COMMAND_CLASS_GENERAL, ///< TCAT commands related to general operations
kCommissioning = OT_TCAT_COMMAND_CLASS_COMMISSIONING, ///< TCAT commands related to commissioning
kExtraction = OT_TCAT_COMMAND_CLASS_EXTRACTION, ///< TCAT commands related to key extraction
kDecommissioning = OT_TCAT_COMMAND_CLASS_DECOMMISSIONING, ///< TCAT commands related to decommissioning
kApplication = OT_TCAT_COMMAND_CLASS_APPLICATION, ///< TCAT commands related to application layer
kInvalid ///< TCAT command belongs to reserved pool or is invalid
};
@@ -109,8 +109,9 @@ public:
kPskdFlag = 1 << 1, ///< Access requires proof-of-possession of the device's PSKd
kNetworkNameFlag = 1 << 2, ///< Access requires matching network name
kExtendedPanIdFlag = 1 << 3, ///< Access requires matching XPANID
kThreadDomainFlag = 1 << 4, ///< Access requires matching XPANID
kThreadDomainFlag = 1 << 4, ///< Access requires matching Thread Domain Name
kPskcFlag = 1 << 5, ///< Access requires proof-of-possession of the device's PSKc
kMaxFlag = 1 << 6, ///< Maximum value of access flags
};
/**
@@ -151,47 +152,50 @@ public:
enum CommandTlvType : uint8_t
{
// Command Class General
kTlvResponseWithStatus = 1, ///< TCAT response with status value TLV
kTlvResponseWithPayload = 2, ///< TCAT response with payload TLV
kTlvResponseEvent = 3, ///< TCAT response event TLV (reserved)
kTlvGetNetworkName = 8, ///< TCAT network name query TLV
kTlvDisconnect = 9, ///< TCAT disconnect request TLV
kTlvPing = 10, ///< TCAT ping request TLV
kTlvGetDeviceId = 11, ///< TCAT device ID query TLV
kTlvGetExtendedPanID = 12, ///< TCAT extended PAN ID query TLV
kTlvGetProvisioningURL = 13, ///< TCAT provisioning URL query TLV
kTlvPresentPskdHash = 16, ///< TCAT commissioner rights elevation request TLV using PSKd hash
kTlvPresentPskcHash = 17, ///< TCAT commissioner rights elevation request TLV using PSKc hash
kTlvPresentInstallCodeHash = 18, ///< TCAT commissioner rights elevation request TLV using install code
kTlvRequestRandomNumChallenge = 19, ///< TCAT random number challenge query TLV
kTlvRequestPskdHash = 20, ///< TCAT PSKd hash request TLV
kTlvResponseWithStatus = 0x01, ///< TCAT response with status value TLV
kTlvResponseWithPayload = 0x02, ///< TCAT response with payload TLV
kTlvResponseEvent = 0x03, ///< TCAT response event TLV (reserved)
kTlvGetNetworkName = 0x08, ///< TCAT network name query TLV
kTlvDisconnect = 0x09, ///< TCAT disconnect request TLV
kTlvPing = 0x0A, ///< TCAT ping request TLV
kTlvGetDeviceId = 0x0B, ///< TCAT device ID query TLV
kTlvGetExtendedPanID = 0x0C, ///< TCAT extended PAN ID query TLV
kTlvGetProvisioningURL = 0x0D, ///< TCAT provisioning URL query TLV
kTlvPresentPskdHash = 0x10, ///< TCAT commissioner rights elevation request TLV using PSKd hash
kTlvPresentPskcHash = 0x11, ///< TCAT commissioner rights elevation request TLV using PSKc hash
kTlvPresentInstallCodeHash = 0x12, ///< TCAT commissioner rights elevation request TLV using install code
kTlvRequestRandomNumChallenge = 0x13, ///< TCAT random number challenge query TLV
kTlvRequestPskdHash = 0x14, ///< TCAT PSKd hash request TLV
// Command Class Commissioning
kTlvSetActiveOperationalDataset = 32, ///< TCAT active operational dataset TLV
kTlvSetActiveOperationalDatasetAlternative = 33, ///< TCAT active operational dataset alternative #1 TLV
kTlvGetProvisioningTlvs = 36, ///< TCAT provisioning TLVs query TLV
kTlvGetCommissionerCertificate = 37, ///< TCAT commissioner certificate query TLV
kTlvGetDiagnosticTlvs = 38, ///< TCAT diagnostics TLVs query TLV
kTlvStartThreadInterface = 39, ///< TCAT start thread interface request TLV
kTlvStopThreadInterface = 40, ///< TCAT stop thread interface request TLV
kTlvSetActiveOperationalDataset = 0x20, ///< TCAT active operational dataset TLV
kTlvSetActiveOperationalDatasetAlternative = 0x21, ///< TCAT active operational dataset alternative #1 TLV
kTlvGetCommissionerCertificate = 0x25, ///< TCAT commissioner certificate query TLV
kTlvGetDiagnosticTlvs = 0x26, ///< TCAT diagnostics TLVs query TLV
kTlvStartThreadInterface = 0x27, ///< TCAT start thread interface request TLV
kTlvStopThreadInterface = 0x28, ///< TCAT stop thread interface request TLV
// Command Class Extraction
kTlvGetActiveOperationalDataset = 64, ///< TCAT active oerational dataset query TLV
kTlvGetActiveOperationalDatasetAlternative = 65, ///< TCAT active oerational dataset alternative #1 query TLV
kTlvGetActiveOperationalDataset = 0x40, ///< TCAT active oerational dataset query TLV
kTlvGetActiveOperationalDatasetAlternative = 0x41, ///< TCAT active oerational dataset alternative #1 query TLV
// Command Class Decommissioning
kTlvDecommission = 96, ///< TCAT decommission request TLV
kTlvDecommission = 0x60, ///< TCAT decommission request TLV
// Command Class Application
kTlvSelectApplicationLayerUdp = 128, ///< TCAT select UDP protocol application layer request TLV
kTlvSelectApplicationLayerTcp = 129, ///< TCAT select TCP protocol application layer request TLV
kTlvSendApplicationData = 130, ///< TCAT send application data TLV
kTlvSendVendorSpecificData = 159, ///< TCAT send vendor specific command or data TLV
kTlvGetApplicationLayers = 0x80, ///< TCAT get application layers request TLV
kTlvSendApplicationData1 = 0x81, ///< TCAT send application data 1 TLV
kTlvSendApplicationData2 = 0x82, ///< TCAT send application data 2 TLV
kTlvSendApplicationData3 = 0x83, ///< TCAT send application data 3 TLV
kTlvSendApplicationData4 = 0x84, ///< TCAT send application data 4 TLV
kTlvServiceNameUdp = 0x89, ///< TCAT service name UDP sub-TLV (not used as a command)
kTlvServiceNameTcp = 0x8A, ///< TCAT service name TCP sub-TLV (not used as a command)
kTlvSendVendorSpecificData = 0x9F, ///< TCAT send vendor specific command or data TLV
// Command Class CCM
kTlvSetLDevIdOperationalCert = 160, ///< TCAT LDevID operational certificate TLV
kTlvSetLDevIdPrivateKey = 161, ///< TCAT LDevID operational certificate pricate key TLV
kTlvSetDomainCaCert = 162, ///< TCAT domain CA certificate TLV
kTlvSetLDevIdOperationalCert = 0xA0, ///< TCAT LDevID operational certificate TLV
kTlvSetLDevIdPrivateKey = 0xA1, ///< TCAT LDevID operational certificate pricate key TLV
kTlvSetDomainCaCert = 0xA2, ///< TCAT domain CA certificate TLV
};
/**
@@ -208,6 +212,8 @@ public:
kStatusUndefined = OT_TCAT_STATUS_UNDEFINED, ///< The requested value, data or service is not defined
///< (currently) or not present
kStatusHashError = OT_TCAT_STATUS_HASH_ERROR, ///< The hash value presented by the commissioner was incorrect
kStatusInvalidState =
OT_TCAT_STATUS_INVALID_STATE, ///< The TCAT device is in invalid state to execute the command
kStatusUnauthorized =
OT_TCAT_STATUS_UNAUTHORIZED, ///< Sender does not have sufficient authorization for the given command
};
@@ -219,8 +225,16 @@ public:
{
kApplicationProtocolNone =
OT_TCAT_APPLICATION_PROTOCOL_NONE, ///< Message which has been sent without activating the TCAT agent
kApplicationProtocolUdp = OT_TCAT_APPLICATION_PROTOCOL_STATUS, ///< Message directed to a UDP service
kApplicationProtocolTcp = OT_TCAT_APPLICATION_PROTOCOL_TCP, ///< Message directed to a TCP service
kApplicationProtocolStatus = OT_TCAT_APPLICATION_PROTOCOL_STATUS, ///< Message directed to any application
///< indicating a response with status value
kApplicationProtocolResponse = OT_TCAT_APPLICATION_PROTOCOL_RESPONSE, ///< Message directed to any application
///< indicating a response with payload
kApplicationProtocol1 = OT_TCAT_APPLICATION_PROTOCOL_1, ///< Message directed to application 1
kApplicationProtocol2 = OT_TCAT_APPLICATION_PROTOCOL_2, ///< Message directed to application 2
kApplicationProtocol3 = OT_TCAT_APPLICATION_PROTOCOL_3, ///< Message directed to application 3
kApplicationProtocol4 = OT_TCAT_APPLICATION_PROTOCOL_4, ///< Message directed to application 4
kApplicationProtocolVendor =
OT_TCAT_APPLICATION_PROTOCOL_VENDOR, ///< Message directed to a vendor specific application
};
/**
@@ -332,6 +346,8 @@ public:
* @retval FALSE The install code was not verified.
*/
bool GetInstallCodeVerifyStatus(void) const { return mInstallCodeVerified; }
bool GetApplicationResponsePending(void) { return mApplicationResponsePending; }
void NotifyApplicationResponseSent(void) { mApplicationResponsePending = false; }
private:
Error Connected(MeshCoP::Tls::Extension &aTls);
@@ -365,7 +381,13 @@ private:
uint16_t aLength,
bool &aResponse);
Error HandleStartThreadInterface(void);
Error HandleStopThreadInterface(void);
Error HandleGetCommissionerCertificate(Message &aOutgoingMessage, bool &aResponse);
Error HandleGetApplicationLayers(Message &aOutgoingMessage, bool &aResponse);
Error HandleApplicationData(const Message &aIncomingMessage,
uint16_t aOffset,
TcatApplicationProtocol aApplicationProtocol,
bool &aResponse);
Error VerifyHash(const Message &aIncomingMessage,
uint16_t aOffset,
@@ -374,12 +396,10 @@ private:
size_t aBufLen);
void CalculateHash(uint64_t aChallenge, const char *aBuf, size_t aBufLen, Crypto::HmacSha256::Hash &aHash);
bool CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags,
CommandClassFlags aDeviceCommandClassFlags,
Dataset *aDataset) const;
bool CanProcessTlv(uint8_t aTlvType) const;
CommandClass GetCommandClass(uint8_t aTlvType) const;
bool CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags,
CommandClassFlags aDeviceCommandClassFlags,
Dataset *aDataset) const;
uint8_t CheckAuthorizationRequirements(CommandClassFlags aFlagsChecked, Dataset::Info *aDatasetInfo) const;
static constexpr uint16_t kJoinerUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT;
static constexpr uint16_t kPingPayloadMaxLength = 512;
@@ -389,6 +409,8 @@ private:
static constexpr uint16_t kInstallCodeMaxSize = 255;
static constexpr uint16_t kCommissionerCertMaxLength = 1024;
static constexpr uint16_t kBufferReserve = 2048 / (kBufferSize - sizeof(otMessageBuffer)) + 1;
static constexpr uint8_t kServiceNameMaxLength = OT_TCAT_SERVICE_NAME_MAX_LENGTH;
static constexpr uint8_t kApplicationLayerMaxCount = OT_TCAT_APPLICATION_LAYER_MAX_COUNT;
JoinerPskd mJoinerPskd;
const VendorInfo *mVendorInfo;
@@ -396,11 +418,9 @@ private:
Callback<AppDataReceiveCallback> mAppDataReceiveCallback;
CertificateAuthorizationField mCommissionerAuthorizationField;
CertificateAuthorizationField mDeviceAuthorizationField;
TcatApplicationProtocol mCurrentApplicationProtocol;
NetworkName mCommissionerNetworkName;
NetworkName mCommissionerDomainName;
ExtendedPanId mCommissionerExtendedPanId;
char mCurrentServiceName[OT_TCAT_MAX_SERVICE_NAME_LENGTH + 1];
State mState;
bool mCommissionerHasNetworkName : 1;
bool mCommissionerHasDomainName : 1;
@@ -409,6 +429,8 @@ private:
bool mPskdVerified : 1;
bool mPskcVerified : 1;
bool mInstallCodeVerified : 1;
bool mIsCommissioned : 1;
bool mApplicationResponsePending : 1;
friend class Ble::BleSecure;
};
@@ -429,9 +451,9 @@ typedef UintTlvInfo<MeshCoP::TcatAgent::kTlvResponseWithStatus, uint8_t> Respons
struct DeviceTypeAndStatus
{
uint8_t mRsv : 1;
bool mMultiradioSupport : 1;
bool mStoresActiveOpertonalDataset : 1;
bool mIsCommisionned : 1;
bool mMultiRadioSupport : 1;
bool mStoresActiveOperationalDataset : 1;
bool mIsCommissioned : 1;
bool mThreadNetworkActive : 1;
bool mIsBorderRouter : 1;
bool mRxOnWhenIdle : 1;
+40 -6
View File
@@ -27,6 +27,7 @@
*/
#include "ble_secure.hpp"
#include "common/error.hpp"
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
@@ -161,9 +162,27 @@ void BleSecure::Disconnect(void)
IgnoreError(otPlatBleGapDisconnect(&GetInstance()));
}
// Update advertisement
IgnoreError(NotifyAdvertisementChanged());
mConnectCallback.InvokeIfSet(&GetInstance(), false, false);
}
Error BleSecure::NotifyAdvertisementChanged(void)
{
Error error = kErrorNone;
uint16_t advertisementLen = 0;
uint8_t *advertisementData = nullptr;
VerifyOrExit(mBleState == kAdvertising);
SuccessOrExit(error = otPlatBleGetAdvertisementBuffer(&GetInstance(), &advertisementData));
SuccessOrExit(error = mTcatAgent.GetAdvertisementData(advertisementLen, advertisementData));
SuccessOrExit(error = otPlatBleGapAdvUpdateData(&GetInstance(), advertisementData, advertisementLen));
exit:
return error;
}
void BleSecure::SetPsk(const MeshCoP::JoinerPskd &aPskd)
{
static_assert(static_cast<uint16_t>(MeshCoP::JoinerPskd::kMaxLength) <=
@@ -207,14 +226,22 @@ exit:
return error;
}
Error BleSecure::SendApplicationTlv(uint8_t *aBuf, uint16_t aLength)
Error BleSecure::SendApplicationTlv(MeshCoP::TcatAgent::TcatApplicationProtocol aTcatApplicationProtocol,
uint8_t *aBuf,
uint16_t aLength)
{
Error error = kErrorNone;
VerifyOrExit((aTcatApplicationProtocol != MeshCoP::TcatAgent::kApplicationProtocolStatus &&
aTcatApplicationProtocol != MeshCoP::TcatAgent::kApplicationProtocolResponse) ||
mTcatAgent.GetApplicationResponsePending(),
error = kErrorRejected);
if (aLength > Tlv::kBaseTlvMaxLength)
{
ot::ExtendedTlv tlv;
tlv.SetType(ot::MeshCoP::TcatAgent::kTlvSendApplicationData);
tlv.SetType(static_cast<uint8_t>(aTcatApplicationProtocol));
tlv.SetLength(aLength);
SuccessOrExit(error = Send(reinterpret_cast<uint8_t *>(&tlv), sizeof(tlv)));
}
@@ -222,12 +249,19 @@ Error BleSecure::SendApplicationTlv(uint8_t *aBuf, uint16_t aLength)
{
ot::Tlv tlv;
tlv.SetType(ot::MeshCoP::TcatAgent::kTlvSendApplicationData);
tlv.SetType(static_cast<uint8_t>(aTcatApplicationProtocol));
tlv.SetLength((uint8_t)aLength);
SuccessOrExit(error = Send(reinterpret_cast<uint8_t *>(&tlv), sizeof(tlv)));
}
error = Send(aBuf, aLength);
SuccessOrExit(error = Send(aBuf, aLength));
if (aTcatApplicationProtocol == MeshCoP::TcatAgent::kApplicationProtocolStatus ||
aTcatApplicationProtocol == MeshCoP::TcatAgent::kApplicationProtocolResponse)
{
mTcatAgent.NotifyApplicationResponseSent();
}
exit:
return error;
}
@@ -390,7 +424,7 @@ void BleSecure::HandleTlsReceive(uint8_t *aBuf, uint16_t aLength)
if (!mTlvMode)
{
SuccessOrExit(mReceivedMessage->AppendBytes(aBuf, aLength));
mReceiveCallback.InvokeIfSet(&GetInstance(), mReceivedMessage, 0, OT_TCAT_APPLICATION_PROTOCOL_NONE, "");
mReceiveCallback.InvokeIfSet(&GetInstance(), mReceivedMessage, 0, OT_TCAT_APPLICATION_PROTOCOL_NONE);
IgnoreError(mReceivedMessage->SetLength(0));
}
else
@@ -476,7 +510,7 @@ void BleSecure::HandleTlsReceive(uint8_t *aBuf, uint16_t aLength)
{
mReceivedMessage->SetOffset((uint16_t)offset);
mReceiveCallback.InvokeIfSet(&GetInstance(), mReceivedMessage, (int32_t)offset,
OT_TCAT_APPLICATION_PROTOCOL_NONE, "");
OT_TCAT_APPLICATION_PROTOCOL_NONE);
}
SuccessOrExit(mReceivedMessage->SetLength(0)); // also sets the offset to 0
+19 -6
View File
@@ -221,14 +221,19 @@ public:
/**
* Sends a secure BLE data packet containing a TCAT Send Application Data TLV.
*
* @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV.
* @param[in] aLength A number indicating the length of the data buffer.
* @param[in] aApplicationProtocol An application protocol the data is directed to.
* @param[in] aBuf A pointer to the data to send as the Value of the TCAT application TLV.
* @param[in] aLength A number indicating the length of the data buffer.
*
* @retval kErrorNone Successfully sent data.
* @retval kErrorNoBufs Failed to allocate buffer memory.
* @retval kErrorInvalidState TLS connection was not initialized.
* @retval kErrorNone Successfully sent data.
* @retval kErrorNoBufs Failed to allocate buffer memory.
* @retval kErrorInvalidState TLS connection was not initialized.
* @retval kErrorRejected Application protocol is response with data or status but no response is
* pending.
*/
Error SendApplicationTlv(uint8_t *aBuf, uint16_t aLength);
Error SendApplicationTlv(MeshCoP::TcatAgent::TcatApplicationProtocol aApplicationProtocol,
uint8_t *aBuf,
uint16_t aLength);
/**
* Sends all remaining bytes in the send buffer.
@@ -276,6 +281,14 @@ public:
*/
bool GetInstallCodeVerifyStatus(void) const { return mTcatAgent.GetInstallCodeVerifyStatus(); }
/**
* @brief Notifies the BLE layer that the BLE advertisement data should be updated.
*
* @retval kErrorNone Successfully updated.
* @return kErrorFailed Update failed.
*/
Error NotifyAdvertisementChanged(void);
private:
enum BleState : uint8_t
{
+5
View File
@@ -35,6 +35,7 @@
#include "instance/instance.hpp"
#include "openthread/platform/toolchain.h"
#include "radio/ble_secure.hpp"
#include "utils/static_counter.hpp"
namespace ot {
@@ -353,6 +354,10 @@ void Mle::SetRole(DeviceRole aRole)
break;
}
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
IgnoreError(Get<Ble::BleSecure>().NotifyAdvertisementChanged());
#endif
// If the previous state is disabled, the parent can be in kStateRestored.
if (!IsChild() && oldRole != kRoleDisabled)
{
+8
View File
@@ -102,6 +102,14 @@ otError otPlatBleGapAdvSetData(otInstance *aInstance, uint8_t *aAdvertisementDat
return OT_ERROR_NONE;
}
otError otPlatBleGapAdvUpdateData(otInstance *aInstance, uint8_t *aAdvertisementData, uint16_t aAdvertisementLen)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aAdvertisementData);
OT_UNUSED_VARIABLE(aAdvertisementLen);
return OT_ERROR_NONE;
}
bool otPlatBleSupportsMultiRadio(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
+2
View File
@@ -536,6 +536,8 @@ bool otPlatBleSupportsMultiRadio(otInstance *) { return false; }
otError otPlatBleGapAdvSetData(otInstance *, uint8_t *, uint16_t) { return OT_ERROR_NONE; }
otError otPlatBleGapAdvUpdateData(otInstance *, uint8_t *, uint16_t) { return OT_ERROR_NONE; }
OT_TOOL_WEAK otError otPlatRadioAddCalibratedPower(otInstance *, uint8_t, int16_t, const uint8_t *, uint16_t)
{
return OT_ERROR_NONE;
+2 -2
View File
@@ -266,7 +266,7 @@ proc fail {message} {
error $message
}
proc spawn_tcat_client_for_node {id} {
proc spawn_tcat_client_for_node {id {cert_path "tools/tcat_ble_client/auth"}} {
global tcat_ids
global spawn_id
@@ -275,7 +275,7 @@ proc spawn_tcat_client_for_node {id} {
send "tcat start\n"
expect_line "Done"
spawn python "tools/tcat_ble_client/bbtc.py" --simulation $id --cert_path "tools/tcat_ble_client/auth"
spawn python "tools/tcat_ble_client/bbtc.py" --simulation $id --cert_path $cert_path
expect_line "Done"
set tcat_ids($id) $spawn_id
+48 -1
View File
@@ -31,7 +31,19 @@ source "tests/scripts/expect/_common.exp"
spawn_node 1 "cli"
spawn_tcat_client_for_node 1
spawn_tcat_client_for_node 1 tools/tcat_ble_client/auth-cert/CommCert2
send "commission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x10"
send "random_challenge\n"
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
expect_line "\tLEN:\t8"
send "present_hash pskd JJJJJJ\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x00"
send "commission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
@@ -41,6 +53,41 @@ send "thread start\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x00"
dispose_tcat_client 1
switch_node 1
send "tcat stop\n"
expect_line "Done"
spawn_tcat_client_for_node 1
send "commission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x08"
send "get_dataset\n"
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
expect_line "\tLEN:\t106"
send "decommission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
dispose_tcat_client 1
switch_node 1
send "tcat stop\n"
expect_line "Done"
spawn_tcat_client_for_node 1
send "commission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x00"
send "get_dataset\n"
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
expect_line "\tLEN:\t106"
send "decommission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
+8 -4
View File
@@ -31,11 +31,11 @@ source "tests/scripts/expect/_common.exp"
spawn_node 1 "cli"
spawn_tcat_client_for_node 1
spawn_tcat_client_for_node 1 tools/tcat_ble_client/auth-cert/CommCert2
send "commission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x00"
expect_line "\tVALUE:\t0x10"
send "random_challenge\n"
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
@@ -46,13 +46,17 @@ expect_line "Requested hash is valid."
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
expect_line "\tLEN:\t32"
send "present_hash pskd AAAA\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x07"
send "present_hash pskd JJJJJJ\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x00"
send "present_hash pskd AAAA\n"
send "commission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x07"
expect_line "\tVALUE:\t0x00"
send "present_hash install InstallCode\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
+31 -1
View File
@@ -39,7 +39,7 @@ expect_line "\tVALUE:\t0x06"
send "get_dataset\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x04"
expect_line "\tVALUE:\t0x06"
send "get_comm_cert\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
@@ -94,6 +94,36 @@ expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
expect_line "\tLEN:\t9"
expect_line "\tVALUE:\t0x64756d6d795f75726c"
send "get_apps\n"
expect_line "\tApplication 1 is UDP service: echo"
expect_line "\tApplication 2 is TCP service: discard"
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
expect_line "\tLEN:\t15"
expect_line "\tVALUE:\t0x89046563686f8a0764697363617264"
send "appdata1 1122334455667788\n"
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
expect_line "\tLEN:\t8"
expect_line "\tVALUE:\t0x1122334455667788"
send "appdata2 1122334455667788\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x00"
send "appdata3 1122334455667788\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x01"
send "appdata4 1122334455667788\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x01"
send "vendor_data 74657874\n"
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
expect_line "\tLEN:\t4"
expect_line "\tVALUE:\t0x74657874"
dispose_tcat_client 1
switch_node 1
+8
View File
@@ -858,6 +858,14 @@ otError otPlatBleGapAdvSetData(otInstance *aInstance, uint8_t *aAdvertisementDat
return OT_ERROR_NONE;
}
otError otPlatBleGapAdvUpdateData(otInstance *aInstance, uint8_t *aAdvertisementData, uint16_t aAdvertisementLen)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aAdvertisementData);
OT_UNUSED_VARIABLE(aAdvertisementLen);
return OT_ERROR_NONE;
}
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
+96 -1
View File
@@ -107,7 +107,102 @@ class HelloCommand(BleCommand):
return 'Send round trip "Hello world!" message.'
def prepare_data(self, args, context):
return TLV(TcatTLVType.APPLICATION.value, bytes('Hello world!', 'ascii')).to_bytes()
return TLV(TcatTLVType.VENDOR_APPLICATION.value, bytes('Hello world!', 'ascii')).to_bytes()
class GetApplicationLayersCommand(BleCommand):
def get_log_string(self) -> str:
return 'Getting application layers....'
def get_help_string(self) -> str:
return 'Get supported application layer service names from device.'
def prepare_data(self, args, context):
return TLV(TcatTLVType.GET_APPLICATION_LAYERS.value, bytes()).to_bytes()
def process_response(self, tlv_response, context):
if tlv_response.type == TcatTLVType.RESPONSE_W_PAYLOAD.value:
payload = tlv_response.value
i = 0
print('Service names:')
while payload:
tlv_application = TLV.from_bytes(payload)
payload = payload[2 + len(tlv_application.value):]
i += 1
if (tlv_application.type == TcatTLVType.SERVICE_NAME_UDP.value):
print(f"\tApplication {i} is UDP service: {tlv_application.value.decode('ascii')}")
elif (tlv_application.type == TcatTLVType.SERVICE_NAME_TCP.value):
print(f"\tApplication {i} is TCP service: {tlv_application.value.decode('ascii')}")
else:
print('\tUnknown service type.')
else:
print('Dataset extraction error.')
class SendApplicationData1(BleCommand):
def get_log_string(self) -> str:
return 'Sending data to application layer 1....'
def get_help_string(self) -> str:
return 'Send hex encoded data to application layer 1.'
def prepare_data(self, args, context):
payload = bytes.fromhex(args[0])
return TLV(TcatTLVType.APPLICATION_DATA_1.value, payload).to_bytes()
class SendApplicationData2(BleCommand):
def get_log_string(self) -> str:
return 'Sending data to application layer 2....'
def get_help_string(self) -> str:
return 'Send hex encoded data to application layer 2.'
def prepare_data(self, args, context):
payload = bytes.fromhex(args[0])
return TLV(TcatTLVType.APPLICATION_DATA_2.value, payload).to_bytes()
class SendApplicationData3(BleCommand):
def get_log_string(self) -> str:
return 'Sending data to application layer 3....'
def get_help_string(self) -> str:
return 'Send hex encoded data to application layer 3.'
def prepare_data(self, args, context):
payload = bytes.fromhex(args[0])
return TLV(TcatTLVType.APPLICATION_DATA_3.value, payload).to_bytes()
class SendApplicationData4(BleCommand):
def get_log_string(self) -> str:
return 'Sending data to application layer 4....'
def get_help_string(self) -> str:
return 'Send hex encoded data to application layer 4.'
def prepare_data(self, args, context):
payload = bytes.fromhex(args[0])
return TLV(TcatTLVType.APPLICATION_DATA_4.value, payload).to_bytes()
class SendVendorData(BleCommand):
def get_log_string(self) -> str:
return 'Sending data to vendor specific application layer....'
def get_help_string(self) -> str:
return 'Send hex encoded data to vendor specific application layer.'
def prepare_data(self, args, context):
payload = bytes.fromhex(args[0])
return TLV(TcatTLVType.VENDOR_APPLICATION.value, payload).to_bytes()
class CommissionCommand(BleCommand):
+8 -1
View File
@@ -33,7 +33,8 @@ from cli.base_commands import (DisconnectCommand, HelpCommand, HelloCommand, Com
ExtractDatasetCommand, GetCommissionerCertificate, GetDeviceIdCommand, GetPskdHash,
GetExtPanIDCommand, GetNetworkNameCommand, GetProvisioningUrlCommand, PingCommand,
GetRandomNumberChallenge, ThreadStateCommand, ScanCommand, PresentHash,
DiagnosticTlvsCommand)
DiagnosticTlvsCommand, GetApplicationLayersCommand, SendVendorData,
SendApplicationData1, SendApplicationData2, SendApplicationData3, SendApplicationData4)
from .tlv_commands import TlvCommand
from cli.dataset_commands import (DatasetCommand)
from dataset.dataset import ThreadDataset
@@ -49,6 +50,12 @@ class CLI:
self._commands = {
'help': HelpCommand(),
'hello': HelloCommand(),
'get_apps': GetApplicationLayersCommand(),
'appdata1': SendApplicationData1(),
'appdata2': SendApplicationData2(),
'appdata3': SendApplicationData3(),
'appdata4': SendApplicationData4(),
'vendor_data': SendVendorData(),
'commission': CommissionCommand(),
'decommission': DecommissionCommand(),
'disconnect': DisconnectCommand(),
+1 -4
View File
@@ -90,10 +90,7 @@ class CommandResultTLV(CommandResult):
else:
print(f'\tTYPE:\tunknown: {hex(tlv.type)} ({tlv.type})')
print(f'\tLEN:\t{len(tlv.value)}')
if tlv_type == TcatTLVType.APPLICATION:
print(f'\tVALUE:\t{tlv.value.decode("ascii")}')
else:
print(f'\tVALUE:\t0x{tlv.value.hex()}')
print(f'\tVALUE:\t0x{tlv.value.hex()}')
class CommandResultNone(CommandResult):
@@ -22,6 +22,8 @@ from abc import ABC, abstractmethod
from tlv.dataset_tlv import MeshcopTlvType
from tlv.tlv import TLV
MASK_48_BITS = 0xFFFFFFFFFFFF
class DatasetEntry(ABC):
@@ -66,13 +68,13 @@ class ActiveTimestamp(DatasetEntry):
def set(self, args: List[str]):
if len(args) == 0:
raise ValueError('No argument for ActiveTimestamp')
self._seconds = int(args[0])
self.seconds = int(args[0])
def set_from_tlv(self, tlv: TLV):
(value,) = struct.unpack('>Q', tlv.value)
self.ubit = value & 0x1
self.ticks = (value >> 1) & 0x7FFF
self.seconds = (value >> 16) & 0xFFFF
self.seconds = (value >> 16) & MASK_48_BITS
def to_tlv(self):
value = (self.seconds << 16) | (self.ticks << 1) | self.ubit
@@ -92,7 +94,7 @@ class PendingTimestamp(DatasetEntry):
def set(self, args: List[str]):
if len(args) == 0:
raise ValueError('No argument for PendingTimestamp')
self._seconds = int(args[0])
self.seconds = int(args[0])
def set_from_tlv(self, tlv: TLV):
(value,) = struct.unpack('>Q', tlv.value)
@@ -476,6 +478,30 @@ class ChannelMaskEntry(DatasetEntry):
return TLV.from_bytes(tlv)
class WakeupChannel(DatasetEntry):
def __init__(self):
super().__init__(MeshcopTlvType.WAKEUP_CHANNEL)
self.length = 3 # spec defined
self.channel_page = 0
self.channel = 0
def set(self, args: List[str]):
if len(args) == 0:
raise ValueError('No argument for WakeupChannel')
channel = int(args[0])
self.channel = channel
def set_from_tlv(self, tlv: TLV):
self.channel = int.from_bytes(tlv.value[1:3], byteorder='big')
self.channel_page = tlv.value[0]
def to_tlv(self):
tlv = struct.pack('>BBB', self.type.value, self.length, self.channel_page)
tlv += struct.pack('>H', self.channel)
return TLV.from_bytes(tlv)
ENTRY_CLASSES = {
MeshcopTlvType.ACTIVETIMESTAMP: ActiveTimestamp,
MeshcopTlvType.PENDINGTIMESTAMP: PendingTimestamp,
@@ -488,7 +514,8 @@ ENTRY_CLASSES = {
MeshcopTlvType.CHANNEL: Channel,
MeshcopTlvType.PSKC: Pskc,
MeshcopTlvType.SECURITYPOLICY: SecurityPolicy,
MeshcopTlvType.CHANNELMASK: ChannelMask
MeshcopTlvType.CHANNELMASK: ChannelMask,
MeshcopTlvType.WAKEUP_CHANNEL: WakeupChannel
}
+52 -45
View File
@@ -1,14 +1,14 @@
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
[[package]]
name = "async-timeout"
version = "4.0.2"
version = "4.0.3"
description = "Timeout context manager for asyncio programs"
optional = false
python-versions = ">=3.6"
python-versions = ">=3.7"
files = [
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
{file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
]
[package.dependencies]
@@ -67,54 +67,61 @@ files = [
[[package]]
name = "dbus-fast"
version = "1.90.1"
version = "1.95.2"
description = "A faster version of dbus-next"
optional = false
python-versions = ">=3.7,<4.0"
files = [
{file = "dbus_fast-1.90.1-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:657f9f292f770b50c755bc9cc3607ec0901a607d6d6e31c67aa953b73b31d66a"},
{file = "dbus_fast-1.90.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:229cb2dc0942dfe36ce4f5a49cacb7f39ae05527c6ccec66b9a670ca7a02129a"},
{file = "dbus_fast-1.90.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:4978d6dca49b778c426f279f014554e29ece6bfc7530fa8ab9d258f068e5954e"},
{file = "dbus_fast-1.90.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2161851a1f90a1c2fe064d1870b04bdca0033b42fdc97cc7d5132637227ac915"},
{file = "dbus_fast-1.90.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0012799b154fb6b066ff6948f5edd0c6bf8655fca6f3578fc78598334f9f978b"},
{file = "dbus_fast-1.90.1-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0b97748928e3e56bc98f292be894d1d3c2a4acc58555795a3aa3b74769b96542"},
{file = "dbus_fast-1.90.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2baa2e1053ded0a5ccdefc651ee8fcd09d6f4f864b9f301363dbf0545f95a89"},
{file = "dbus_fast-1.90.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0262ab1d3d07ac892645d4cec54daabd3ba4a096ca4c4b2e9f09abd1819ca663"},
{file = "dbus_fast-1.90.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c39a352a893923d255031d15fa005ac5f5df2d1195729f206fc79a95b219daed"},
{file = "dbus_fast-1.90.1-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:bd012a0ed7e6479bcc5b0efe91a45c3abb3e0e4e371a28c0f3c347cb9baffe8a"},
{file = "dbus_fast-1.90.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3e895adfa89a6c08d23fd22707bd5ea8a301579f3a6ff8bd33df1e94ea16e8a"},
{file = "dbus_fast-1.90.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a94806e9990b6a7fd4896ee2a979c20af4e5ba76bfddda55a7a79f4da268b51f"},
{file = "dbus_fast-1.90.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae0b95a08db0a7e38452926c8d5964d41e5f20d8c89fd00b8913ec4f1908f7bd"},
{file = "dbus_fast-1.90.1-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:3ce5153accbbb7fc2aeab055f46d5611c4c57978d43feba9257fba53c338ebbe"},
{file = "dbus_fast-1.90.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3b05b68a7be76df3e4833c72d9fadf1b934359ed3fabd69ed205eaa18d132a6"},
{file = "dbus_fast-1.90.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d407eb9a3581ee5cc047a664d3d15e9846e5a1c0b3565922c72ffe15fea590f2"},
{file = "dbus_fast-1.90.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:85f06e4cbf560e682930f0d23ea93b1887c40db00b98ee4d6a207aa2a616851e"},
{file = "dbus_fast-1.90.1-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:28a4ee863b4a42351afb38ce9432850922dc2f0d9d9863f98fcb47e23b710572"},
{file = "dbus_fast-1.90.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd6090c794ca3404702b59cb4dc92f674e26a15bb79a9d5ae0236658c10cac5"},
{file = "dbus_fast-1.90.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9e7be16e96bcad521f2c045561799fc486047b6e1ce071c35a5cea36a9ed19f4"},
{file = "dbus_fast-1.90.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:01f582d9c3f24e1721f3dd9a62c7a558c7c8406752eb042738623b9d89f454e9"},
{file = "dbus_fast-1.90.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:085fd80c7ea3e41a2ac32e419611036a042593778fecb4d92526a22fd2be2c0b"},
{file = "dbus_fast-1.90.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e0dbffd42875d31d0c7e2407eff685d5cb2dfa7c0448079c96ef2cec0afe8be"},
{file = "dbus_fast-1.90.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:04eaaea336059909b5cb51c897fc343e038e80f698a049b1bf3002d162d4fec7"},
{file = "dbus_fast-1.90.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fc215dbccb798df07ee6104b984ae09c159ed3a633df915c3c6dd9df97af753"},
{file = "dbus_fast-1.90.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:74f7afaf780fbbc7f39cc8167ec585f8e7ce140d214768f5c296c2b03d23e571"},
{file = "dbus_fast-1.90.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f12c7bcec416e28ba1f741e43ad2eef7eb3c677838208cf6a801ced711b508c"},
{file = "dbus_fast-1.90.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c0811b7bdfdce40072fd7c29f0c7e0145982b981bb068efd79a5e43ef14150e5"},
{file = "dbus_fast-1.90.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1f00197e08c7c5837861624fd1afb8e1d8331d4e28e8d2ff01dc17ac2305ae2"},
{file = "dbus_fast-1.90.1.tar.gz", hash = "sha256:eff98b45443681bd8876bbb1444b35112d62e8d12157f004d88ebe5f0481d5b7"},
{file = "dbus_fast-1.95.2-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:69f19fb94ac714b917c51fcc329b51695f085f779841edd6e429170f1f073f47"},
{file = "dbus_fast-1.95.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71e84a7ce3b050745dfb2bcd32ade891ecf6f4b06d3baa4dfe30ad09720a0be"},
{file = "dbus_fast-1.95.2-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:3ffcd1c999599da7806d7887d5ce1e9f0d814aa35af92daecab542c9b70794c1"},
{file = "dbus_fast-1.95.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:85739b90e6f983494c3c7187d4daaa50f4f4369aa1e87e876066de97ca1bcd58"},
{file = "dbus_fast-1.95.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e2c107caefa186919169e07a852edea3d931dfb6112584fa2c6e5653d91c0d2d"},
{file = "dbus_fast-1.95.2-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:99902ca6c10368492fdf5a28321d86c7e92e50fd742f0163599602c442232d29"},
{file = "dbus_fast-1.95.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3241252a744b0960e7eb9dcad2892af2bc695b4f47636bab2f17f6012d914ce"},
{file = "dbus_fast-1.95.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f52ef5edef41a0ed29645d7c6e1ee89b5e8f5e5c1ba9901699dcec9cfaf8d961"},
{file = "dbus_fast-1.95.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9706e10a6c24d4c03d28b1631e3882009964d5207a86cae2b42466635d7546be"},
{file = "dbus_fast-1.95.2-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:3277944b418063ad051e8e49144151962691188b972f1fbca7af39fdef4f8a47"},
{file = "dbus_fast-1.95.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cab158bcf86c4b2e03c2f3453738a61de83c82cbed11f23331ccc9a9aba6d5b1"},
{file = "dbus_fast-1.95.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:17d743d13dbde0691adb98f1a6c87f0cf5617a4c9169b4820972dc8869095c6b"},
{file = "dbus_fast-1.95.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aefa695088405d313c703790ac503ad0b2ac1e4807393f1f02e410b6984aedd0"},
{file = "dbus_fast-1.95.2-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:ffd3665a6fbe318aadac998ae117b19214e0782397c86ab47792a120979783a6"},
{file = "dbus_fast-1.95.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43093d8e42342841c7ac69e236370c31949c35b659032888dae8b3af1fa35e9e"},
{file = "dbus_fast-1.95.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4f4b26849254fafb11656fc8c10f8bce67deab683694e0fc7b56edd891d4e118"},
{file = "dbus_fast-1.95.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:331c4a26e010fd8ad3168b9680f39a7d0765507d3aadcbe5f250da0474877f14"},
{file = "dbus_fast-1.95.2-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:7aee30619c79334980a25a1e94299a751b3f276644ec0a69c76bfe57be184e7a"},
{file = "dbus_fast-1.95.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c5d344e3fe3c4b16593fad70448c66ca3130c8c692c74a921c15f18650581a7"},
{file = "dbus_fast-1.95.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9180d4d39d8688b9d8d43f427f0f2883354fa9df18a1f46d14f1762b82249d1f"},
{file = "dbus_fast-1.95.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e19173e65967581186666a47cd0af06111c7e957fb529198e532b35a47171460"},
{file = "dbus_fast-1.95.2-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:fae11a8ed320013decd2bf6a982f010fff011bf935c4f32141e804ba7963719b"},
{file = "dbus_fast-1.95.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f653085d9f96ed2e48434ba951cf4bf0229cc273a87b9799e7cf3a9a6612a56"},
{file = "dbus_fast-1.95.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05d53e0db08de6b3ba43eb110e01b9e6264e7143849ea9772af45b15575c21b2"},
{file = "dbus_fast-1.95.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e73b7dcbac5f418bd4b334ad112e40e8b3bc05c53a3fc451926450ce3bb805e"},
{file = "dbus_fast-1.95.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:76fb9d11bd6ebe1f832350ec57ada352f096f24b5731e38bcbad86ab9b27190b"},
{file = "dbus_fast-1.95.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26045c50bbd8c1674814759332333799b073216b2b2cac9e1cfebf757c7f926d"},
{file = "dbus_fast-1.95.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:bd68b5e7d7c6cd10d804d072062100a4893ad0c19bdac03b53b1809c51a4e3c7"},
{file = "dbus_fast-1.95.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea2692efe0d6d6d58fb427cd0ed53ab44ced0c2ada642b0c15fd139c60a706d6"},
{file = "dbus_fast-1.95.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:33cee333a15241e516ee84aaabdd952dbb1a63f9e986028574451475e97a113f"},
{file = "dbus_fast-1.95.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dfd99cf624f769cf838e62d75ceb737b2866b1783a4f11a928cf38e4c906a5f"},
{file = "dbus_fast-1.95.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b842e94140e39a196d4d83e02eddcbc461b906871ba02f1c5374055f2d628c47"},
{file = "dbus_fast-1.95.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08ca9968dd46b854e5c7b00be32cb273edaf17ddc9647811ff63ae3b9dca822d"},
{file = "dbus_fast-1.95.2.tar.gz", hash = "sha256:3dd64c5cd362ceead6cc02603b6b4cbda58b2cbb6ec816a2f21b1901dfc3cb61"},
]
[[package]]
name = "exceptiongroup"
version = "1.1.2"
version = "1.3.0"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
files = [
{file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"},
{file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"},
{file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"},
{file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"},
]
[package.dependencies]
typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""}
[package.extras]
test = ["pytest (>=6)"]
@@ -151,13 +158,13 @@ files = [
[[package]]
name = "packaging"
version = "23.1"
version = "24.0"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
{file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
{file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
]
[[package]]
@@ -254,13 +261,13 @@ pyobjc-core = ">=9.2"
[[package]]
name = "pytest"
version = "7.4.0"
version = "7.4.4"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.7"
files = [
{file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"},
{file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"},
{file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"},
{file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"},
]
[package.dependencies]
+2
View File
@@ -67,6 +67,8 @@ class MeshcopTlvType(Enum):
PERIOD = 55
SCAN_DURATION = 56
ENERGY_LIST = 57
THREAD_DOMAIN_NAME = 59
WAKEUP_CHANNEL = 74
DISCOVERYREQUEST = 128
DISCOVERYRESPONSE = 129
JOINERADVERTISEMENT = 241
+8 -1
View File
@@ -47,7 +47,14 @@ class TcatTLVType(Enum):
GET_ACTIVE_DATASET = 0x40
GET_DIAGNOSTIC_TLVS = 0x26
DECOMMISSION = 0x60
APPLICATION = 0x82
GET_APPLICATION_LAYERS = 0x80
APPLICATION_DATA_1 = 0x81
APPLICATION_DATA_2 = 0x82
APPLICATION_DATA_3 = 0x83
APPLICATION_DATA_4 = 0x84
SERVICE_NAME_UDP = 0x89
SERVICE_NAME_TCP = 0x8A
VENDOR_APPLICATION = 0x9F
THREAD_START = 0x27
THREAD_STOP = 0x28