Skip to content

Commit

Permalink
[simulation] Adding simulation tests framework for tcat.
Browse files Browse the repository at this point in the history
This commit adds simulation framework for tcat based on posix udp
sockets.
  • Loading branch information
canisLupus1313 committed Mar 18, 2024
1 parent 9d6321b commit 3f26fce
Show file tree
Hide file tree
Showing 9 changed files with 325 additions and 27 deletions.
157 changes: 149 additions & 8 deletions examples/platforms/simulation/ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,50 +26,191 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

#include "platform-simulation.h"

#include <errno.h>

#include <stdio.h>
#include <stdlib.h>
#include <openthread/platform/ble.h>

#include "openthread/error.h"
#include "utils/code_utils.h"

#define PLAT_BLE_MSG_DATA_MAX 2048
static uint8_t sBleBuffer[PLAT_BLE_MSG_DATA_MAX];

static int sFd = -1;

static const uint16_t kPortBase = 10000;
static uint16_t sPort = 0;
struct sockaddr_in sSockaddr;

static void initFds(void)
{
int fd;
int one = 1;
struct sockaddr_in sockaddr;

memset(&sockaddr, 0, sizeof(sockaddr));

sPort = (uint16_t)(kPortBase + gNodeId);
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(sPort);
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sFd)"));

otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != -1,
perror("setsockopt(sFd, SO_REUSEADDR)"));
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != -1,
perror("setsockopt(sFd, SO_REUSEPORT)"));

otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sFd)"));

// Fd is successfully initialized.
sFd = fd;

exit:
if (sFd == -1)
{
exit(EXIT_FAILURE);
}
}

static void deinitFds(void)
{
if (sFd != -1)
{
close(sFd);
sFd = -1;
}
}

otError otPlatBleEnable(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
initFds();
return OT_ERROR_NONE;
}

otError otPlatBleDisable(otInstance *aInstance)
{
deinitFds();
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
return OT_ERROR_NONE;
}

otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aInterval);
return OT_ERROR_NOT_IMPLEMENTED;
return OT_ERROR_NONE;
}

otError otPlatBleGapAdvStop(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
return OT_ERROR_NONE;
}

otError otPlatBleGapDisconnect(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
return OT_ERROR_NONE;
}

otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aMtu);
return OT_ERROR_NOT_IMPLEMENTED;
*aMtu = PLAT_BLE_MSG_DATA_MAX - 1;
return OT_ERROR_NONE;
}

otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aHandle);

ssize_t rval;
otError error = OT_ERROR_NONE;

otEXPECT_ACTION(sFd != -1, error = OT_ERROR_INVALID_STATE);
rval = sendto(sFd, (const char *)aPacket->mValue, aPacket->mLength, 0, (struct sockaddr *)&sSockaddr,
sizeof(sSockaddr));
if (rval == -1)
{
perror("BLE simulation sendto failed.");
}

exit:
return error;
}

void platformBleDeinit(void) { deinitFds(); }

void platformBleUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
{
OT_UNUSED_VARIABLE(aTimeout);
OT_UNUSED_VARIABLE(aWriteFdSet);

if (aReadFdSet != NULL && sFd != -1)
{
FD_SET(sFd, aReadFdSet);

if (aMaxFd != NULL && *aMaxFd < sFd)
{
*aMaxFd = sFd;
}
}
}

void platformBleProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
{
OT_UNUSED_VARIABLE(aWriteFdSet);

otEXPECT(sFd != -1);

if (FD_ISSET(sFd, aReadFdSet))
{
socklen_t len = sizeof(sSockaddr);
ssize_t rval;
memset(&sSockaddr, 0, sizeof(sSockaddr));
rval = recvfrom(sFd, sBleBuffer, sizeof(sBleBuffer), 0, (struct sockaddr *)&sSockaddr, &len);
if (rval > 0)
{
otBleRadioPacket myPacket;
myPacket.mValue = sBleBuffer;
myPacket.mLength = (uint16_t)rval;
myPacket.mPower = 0;
otPlatBleGattServerOnWriteRequest(
aInstance, 0,
&myPacket); // TODO consider passing otPlatBleGattServerOnWriteRequest as a callback function
}
else if (rval == 0)
{
// socket is closed, which should not happen
assert(false);
}
else if (errno != EINTR && errno != EAGAIN)
{
perror("recvfrom BLE simulation failed");
exit(EXIT_FAILURE);
}
}
exit:
return;
}

OT_TOOL_WEAK void otPlatBleGattServerOnWriteRequest(otInstance *aInstance,
uint16_t aHandle,
const otBleRadioPacket *aPacket)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aHandle);
OT_UNUSED_VARIABLE(aPacket);
return OT_ERROR_NOT_IMPLEMENTED;
assert(false);
/* In case of rcp there is a problem with linking to otPlatBleGattServerOnWriteRequest
* which is available in FTD/MTD library.
*/
}
29 changes: 28 additions & 1 deletion examples/platforms/simulation/platform-simulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ void platformRadioDeinit(void);
void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLength);

/**
* Updates the file descriptor sets with file descriptors used by the radio driver.
* Updates the file descriptor sets with file descriptors used by the BLE radio driver.
*
* @param[in,out] aReadFdSet A pointer to the read file descriptors.
* @param[in,out] aWriteFdSet A pointer to the write file descriptors.
Expand Down Expand Up @@ -341,4 +341,31 @@ void platformInfraIfProcess(otInstance *aInstance, const fd_set *aReadFdSet, con

#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE

/**
* Shuts down the BLE service used by OpenThread.
*
*/
void platformBleDeinit(void);

/**
* Updates the file descriptor sets with file descriptors used by the radio driver.
*
* @param[in,out] aReadFdSet A pointer to the read file descriptors.
* @param[in,out] aWriteFdSet A pointer to the write file descriptors.
* @param[in,out] aTimeout A pointer to the timeout.
* @param[in,out] aMaxFd A pointer to the max file descriptor.
*
*/
void platformBleUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd);

/**
* Performs BLE driver processing.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aReadFdSet A pointer to the read file descriptors.
* @param[in] aWriteFdSet A pointer to the write file descriptors.
*
*/
void platformBleProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet);

#endif // PLATFORM_SIMULATION_H_
7 changes: 7 additions & 0 deletions examples/platforms/simulation/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ void otSysProcessDrivers(otInstance *aInstance)
platformInfraIfUpdateFdSet(&read_fds, &write_fds, &max_fd);
#endif

#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
platformBleUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
#endif

if (otTaskletsArePending(aInstance))
{
timeout.tv_sec = 0;
Expand All @@ -308,6 +312,9 @@ void otSysProcessDrivers(otInstance *aInstance)
{
platformUartProcess();
platformRadioProcess(aInstance, &read_fds, &write_fds);
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
platformBleProcess(aInstance, &read_fds, &write_fds);
#endif
}
else if (errno != EINTR)
{
Expand Down
1 change: 1 addition & 0 deletions script/cmake-build
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ OT_POSIX_SIM_COMMON_OPTIONS=(
"-DOT_SRP_CLIENT=ON"
"-DOT_SRP_SERVER=ON"
"-DOT_UPTIME=ON"
"-DOT_BLE_TCAT=ON"
)
readonly OT_POSIX_SIM_COMMON_OPTIONS

Expand Down
61 changes: 61 additions & 0 deletions tests/scripts/expect/cli-tcat.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/expect -f
#
# Copyright (c) 2022, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

source "tests/scripts/expect/_common.exp"

spawn_node 1 "cli"

switch_node 1
send "tcat start\n"
expect_line "Done"

spawn python "/home/pbida/Repos/ncs/modules/lib/openthread/tools/tcat_ble_client/bbtc.py" --simulation 1 --cert_path "tools/tcat_ble_client/auth"
set py_client "$spawn_id"
expect_line "Done"
send "commission\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x00"

send "thread start\n"
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
expect_line "\tVALUE:\t0x00"

send "exit\n"
expect eof

switch_node 1
send "tcat stop\n"
expect_line "Done"

send "networkkey\n"
expect_line "fda7c771a27202e232ecd04cf934f476"
expect_line "Done"

wait_for "state" "leader"
expect_line "Done"
5 changes: 4 additions & 1 deletion third_party/mbedtls/mbedtls-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@

#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
#define MBEDTLS_GCM_C
#endif

#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
Expand Down Expand Up @@ -132,7 +133,9 @@
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#endif

#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#define MBEDTLS_SSL_MAX_CONTENT_LEN 2000 /**< Maxium fragment length in bytes */
#elif OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#define MBEDTLS_SSL_MAX_CONTENT_LEN 900 /**< Maxium fragment length in bytes */
#else
#define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes */
Expand Down
14 changes: 9 additions & 5 deletions tools/tcat_ble_client/bbtc.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from ble.ble_connection_constants import BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, \
BBTC_RX_CHAR_UUID, SERVER_COMMON_NAME
from ble.ble_stream import BleStream
from ble.udp_stream import UdpStream
from ble.ble_stream_secure import BleStreamSecure
from ble import ble_scanner
from cli.cli import CLI
Expand All @@ -47,10 +48,12 @@ async def main():

parser = argparse.ArgumentParser(description='Device parameters')
parser.add_argument('--debug', help='Enable debug logs', action='store_true')
parser.add_argument('--cert_path', help='Path to certificate chain and key', action='store', default='auth')
group = parser.add_mutually_exclusive_group()
group.add_argument('--mac', type=str, help='Device MAC address', action='store')
group.add_argument('--name', type=str, help='Device name', action='store')
group.add_argument('--scan', help='Scan all available devices', action='store_true')
group.add_argument('--simulation', help='Connect to simulation node id', action='store')
args = parser.parse_args()

if args.debug:
Expand All @@ -63,12 +66,11 @@ async def main():

if not (device is None):
print(f'Connecting to {device}')
ble_stream = await BleStream.create(device.address, BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, BBTC_RX_CHAR_UUID)
ble_sstream = BleStreamSecure(ble_stream)
ble_sstream = BleStreamSecure(device)
ble_sstream.load_cert(
certfile=path.join('auth', 'commissioner_cert.pem'),
keyfile=path.join('auth', 'commissioner_key.pem'),
cafile=path.join('auth', 'ca_cert.pem'),
certfile=path.join(args.cert_path, 'commissioner_cert.pem'),
keyfile=path.join(args.cert_path, 'commissioner_key.pem'),
cafile=path.join(args.cert_path, 'ca_cert.pem'),
)

print('Setting up secure channel...')
Expand Down Expand Up @@ -101,6 +103,8 @@ async def get_device_by_args(args):
elif args.scan:
tcat_devices = await ble_scanner.scan_tcat_devices()
device = select_device_by_user_input(tcat_devices)
elif args.simulation:
device = UdpStream("127.0.0.1", int(args.simulation))

return device

Expand Down
Loading

0 comments on commit 3f26fce

Please sign in to comment.