Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ncp] integrate Netif TX/RX with Ncp #2467

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/ncp/ncp_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ void NcpHost::Init(void)
mNcpSpinel.Ip6SetAddressMulticastCallback(
[this](const std::vector<Ip6Address> &aAddrs) { mNetif.UpdateIp6MulticastAddresses(aAddrs); });
mNcpSpinel.NetifSetStateChangedCallback([this](bool aState) { mNetif.SetNetifState(aState); });
mNcpSpinel.Ip6SetReceiveCallback(
[this](const uint8_t *aData, uint16_t aLength) { mNetif.Ip6Receive(aData, aLength); });
}

void NcpHost::Deinit(void)
Expand Down Expand Up @@ -147,6 +149,8 @@ void NcpHost::ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatase
void NcpHost::Process(const MainloopContext &aMainloop)
{
mSpinelDriver.Process(&aMainloop);

mNetif.Process(&aMainloop);
}

void NcpHost::Update(MainloopContext &aMainloop)
Expand All @@ -158,6 +162,8 @@ void NcpHost::Update(MainloopContext &aMainloop)
aMainloop.mTimeout.tv_sec = 0;
aMainloop.mTimeout.tv_usec = 0;
}

mNetif.UpdateFdSet(&aMainloop);
}

} // namespace Ncp
Expand Down
37 changes: 33 additions & 4 deletions src/ncp/ncp_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,13 @@ void NcpSpinel::Ip6SetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask)

otbrError NcpSpinel::Ip6Send(const uint8_t *aData, uint16_t aLength)
{
// TODO: Impelement this function.
OTBR_UNUSED_VARIABLE(aData);
OTBR_UNUSED_VARIABLE(aLength);
otbrError error = OTBR_ERROR_NONE;
EncodingFunc encodingFunc = [this, aData, aLength] { return mEncoder.WriteDataWithLen(aData, aLength); };

SuccessOrExit(SetProperty(SPINEL_PROP_STREAM_NET, encodingFunc), error = OTBR_ERROR_OPENTHREAD);

return OTBR_ERROR_NONE;
exit:
return error;
}

void NcpSpinel::ThreadSetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask)
Expand Down Expand Up @@ -393,6 +395,16 @@ void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, ui
break;
}

case SPINEL_PROP_STREAM_NET:
{
const uint8_t *data;
uint16_t dataLen;

SuccessOrExit(ParseIp6StreamNet(aBuffer, aLength, data, dataLen), error = OTBR_ERROR_PARSE);
SafeInvoke(mIp6ReceiveCallback, data, dataLen);
break;
}

default:
otbrLogWarning("Received uncognized key: %u", aKey);
break;
Expand Down Expand Up @@ -449,6 +461,9 @@ otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid,
}
break;

case SPINEL_PROP_STREAM_NET:
break;

default:
VerifyOrExit(aKey == mWaitingKeyTable[aTid], error = OTBR_ERROR_INVALID_STATE);
break;
Expand Down Expand Up @@ -587,6 +602,20 @@ otError NcpSpinel::ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen,
return error;
}

otError NcpSpinel::ParseIp6StreamNet(const uint8_t *aBuf, uint8_t aLen, const uint8_t *&aData, uint16_t &aDataLen)
{
otError error = OT_ERROR_NONE;
ot::Spinel::Decoder decoder;

VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS);

decoder.Init(aBuf, aLen);
error = decoder.ReadDataWithLen(aData, aDataLen);

exit:
return error;
}

otDeviceRole NcpSpinel::SpinelRoleToDeviceRole(spinel_net_role_t aRole)
{
otDeviceRole role = OT_DEVICE_ROLE_DISABLED;
Expand Down
11 changes: 11 additions & 0 deletions src/ncp/ncp_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class NcpSpinel
using Ip6AddressTableCallback = std::function<void(const std::vector<Ip6AddressInfo> &)>;
using Ip6MulticastAddressTableCallback = std::function<void(const std::vector<Ip6Address> &)>;
using NetifStateChangedCallback = std::function<void(bool)>;
using Ip6ReceiveCallback = std::function<void(const uint8_t *, uint16_t)>;

/**
* Constructor.
Expand Down Expand Up @@ -178,6 +179,14 @@ class NcpSpinel
mIp6MulticastAddressTableCallback = aCallback;
}

/**
* This method sets the callback to receive IP6 datagrams.
*
* @param[in] aCallback The callback to receive IP6 datagrams.
*
*/
void Ip6SetReceiveCallback(const Ip6ReceiveCallback &aCallback) { mIp6ReceiveCallback = aCallback; }

/**
* This methods sends an IP6 datagram through the NCP.
*
Expand Down Expand Up @@ -286,6 +295,7 @@ class NcpSpinel

otError ParseIp6AddressTable(const uint8_t *aBuf, uint16_t aLength, std::vector<Ip6AddressInfo> &aAddressTable);
otError ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector<Ip6Address> &aAddressList);
otError ParseIp6StreamNet(const uint8_t *aBuf, uint8_t aLen, const uint8_t *&aData, uint16_t &aDataLen);

ot::Spinel::SpinelDriver *mSpinelDriver;
uint16_t mCmdTidsInUse; ///< Used transaction ids.
Expand Down Expand Up @@ -314,6 +324,7 @@ class NcpSpinel

Ip6AddressTableCallback mIp6AddressTableCallback;
Ip6MulticastAddressTableCallback mIp6MulticastAddressTableCallback;
Ip6ReceiveCallback mIp6ReceiveCallback;
NetifStateChangedCallback mNetifStateChangedCallback;
};

Expand Down
9 changes: 9 additions & 0 deletions tests/scripts/expect/_common.exp
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,12 @@ proc switch_node {id} {
send_user "\n# ${id}\n"
set spawn_id $spawn_ids($id)
}

proc get_ipaddr {type} {
send "ipaddr $type\n"
expect "ipaddr $type"
set rval [expect_line {([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}}]
expect_line "Done"

return $rval
}
67 changes: 67 additions & 0 deletions tests/scripts/expect/ncp_netif_tx_rx.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/expect -f
#
# Copyright (c) 2024, 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"
Irving-cl marked this conversation as resolved.
Show resolved Hide resolved

set dataset "0e080000000000010000000300001435060004001fffe002087d61eb42cdc48d6a0708fd0d07fca1b9f0500510ba088fc2bd6c3b3897f7a10f58263ff3030f4f70656e5468726561642d353234660102524f04109dc023ccd447b12b50997ef68020f19e0c0402a0f7f8"
set dataset_dbus "0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x14,0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0x7d,0x61,0xeb,0x42,0xcd,0xc4,0x8d,0x6a,0x07,0x08,0xfd,0x0d,0x07,0xfc,0xa1,0xb9,0xf0,0x50,0x05,0x10,0xba,0x08,0x8f,0xc2,0xbd,0x6c,0x3b,0x38,0x97,0xf7,0xa1,0x0f,0x58,0x26,0x3f,0xf3,0x03,0x0f,0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x35,0x32,0x34,0x66,0x01,0x02,0x52,0x4f,0x04,0x10,0x9d,0xc0,0x23,0xcc,0xd4,0x47,0xb1,0x2b,0x50,0x99,0x7e,0xf6,0x80,0x20,0xf1,0x9e,0x0c,0x04,0x02,0xa0,0xf7,0xf8"

# Step 1. Start a Thread node and create a Thread network
spawn_node 1 cli $::env(EXP_OT_CLI_PATH)

send "dataset set active ${dataset}\n"
expect_line "Done"
send "ifconfig up\n"
expect_line "Done"
send "thread start\n"
expect_line "Done"
wait_for "state" "leader"
expect_line "Done"
set dest_addr [get_ipaddr mleid]

# Step 2. Start otbr-agent with a NCP and join the network by dbus join method
spawn_node 2 otbr $::env(EXP_OT_NCP_PATH)
sleep 1

spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.Join "array:byte:${dataset_dbus}"
expect eof

# Step 3. Wait 10 seconds, check if the otbr-agent has attached successfully
sleep 10
spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply --reply-timeout=1000 /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:DeviceRole
expect -re {router|child} {
} timeout {
puts "timeout!"
exit 1
}
expect eof

# Step 4. Verify pinging from otbr-agent NCP to the cli node
spawn ping6 -c 10 ${dest_addr}
expect "10 packets transmitted, 10 received, 0% packet loss"
expect eof
Loading