Skip to content

Commit

Permalink
[ncp] integrate netif wpan tx/rx with NCP
Browse files Browse the repository at this point in the history
  • Loading branch information
Irving-cl committed Sep 5, 2024
1 parent e8ea2d3 commit 474f4c3
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 4 deletions.
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
}
39 changes: 39 additions & 0 deletions tests/scripts/expect/ncp_netif_tx_rx.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
source "tests/scripts/expect/_common.exp"

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

0 comments on commit 474f4c3

Please sign in to comment.