Skip to content

Commit

Permalink
[ncp] integrate netif multicast address subscription (#2498)
Browse files Browse the repository at this point in the history
Applications can listen to a multicast address on wpan interface and
receive multicast messages from the Thread network.

The implementation of `NcpSpinel::Ip6MulAddrUpdateSubscription` uses
`SPINEL_CMD_PROP_VALUE_INSERT` and REMOVE. This commit extends
NcpSpinel to support using these commands.
  • Loading branch information
Irving-cl authored Sep 25, 2024
1 parent d4a8e70 commit dd261f0
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 11 deletions.
117 changes: 109 additions & 8 deletions src/ncp/ncp_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,23 @@ void NcpSpinel::HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_

SuccessOrExit(error = SpinelDataUnpack(aFrame, aLength, kSpinelDataUnpackFormat, &header, &cmd, &key, &data, &len));

VerifyOrExit(cmd == SPINEL_CMD_PROP_VALUE_IS, error = OTBR_ERROR_INVALID_STATE);

switch (mCmdTable[aTid])
{
case SPINEL_CMD_PROP_VALUE_SET:
{
error = HandleResponseForPropSet(aTid, key, data, len);
break;
}
case SPINEL_CMD_PROP_VALUE_INSERT:
{
error = HandleResponseForPropInsert(aTid, cmd, key, data, len);
break;
}
case SPINEL_CMD_PROP_VALUE_REMOVE:
{
error = HandleResponseForPropRemove(aTid, cmd, key, data, len);
break;
}
case SPINEL_CMD_NET_CLEAR:
{
spinel_status_t status = SPINEL_STATUS_OK;
Expand Down Expand Up @@ -473,12 +481,90 @@ otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid,
return error;
}

otbrError NcpSpinel::HandleResponseForPropInsert(spinel_tid_t aTid,
spinel_command_t aCmd,
spinel_prop_key_t aKey,
const uint8_t *aData,
uint16_t aLength)
{
otbrError error = OTBR_ERROR_NONE;

switch (mWaitingKeyTable[aTid])
{
case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE:
if (aCmd == SPINEL_CMD_PROP_VALUE_IS)
{
spinel_status_t status = SPINEL_STATUS_OK;

VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE);
SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
otbrLogInfo("Failed to subscribe to multicast address on NCP, error:%s", spinel_status_to_cstr(status));
}
else
{
error = aCmd == SPINEL_CMD_PROP_VALUE_INSERTED ? OTBR_ERROR_NONE : OTBR_ERROR_INVALID_STATE;
}
break;
default:
break;
}

exit:
otbrLogResult(error, "HandleResponseForPropInsert, key:%u", mWaitingKeyTable[aTid]);
return error;
}

otbrError NcpSpinel::HandleResponseForPropRemove(spinel_tid_t aTid,
spinel_command_t aCmd,
spinel_prop_key_t aKey,
const uint8_t *aData,
uint16_t aLength)
{
otbrError error = OTBR_ERROR_NONE;

switch (mWaitingKeyTable[aTid])
{
case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE:
if (aCmd == SPINEL_CMD_PROP_VALUE_IS)
{
spinel_status_t status = SPINEL_STATUS_OK;

VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE);
SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
otbrLogInfo("Failed to unsubscribe to multicast address on NCP, error:%s", spinel_status_to_cstr(status));
}
else
{
error = aCmd == SPINEL_CMD_PROP_VALUE_REMOVED ? OTBR_ERROR_NONE : OTBR_ERROR_INVALID_STATE;
}
break;
default:
break;
}

exit:
otbrLogResult(error, "HandleResponseForPropRemove, key:%u", mWaitingKeyTable[aTid]);
return error;
}

otbrError NcpSpinel::Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded)
{
OTBR_UNUSED_VARIABLE(aAddress);
OTBR_UNUSED_VARIABLE(aIsAdded);
otbrError error = OTBR_ERROR_NONE;
EncodingFunc encodingFunc = [this, aAddress] { return mEncoder.WriteIp6Address(aAddress); };

return OTBR_ERROR_NOT_IMPLEMENTED;
if (aIsAdded)
{
SuccessOrExit(InsertProperty(SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, encodingFunc),
error = OTBR_ERROR_OPENTHREAD);
}
else
{
SuccessOrExit(RemoveProperty(SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, encodingFunc),
error = OTBR_ERROR_OPENTHREAD);
}

exit:
return error;
}

spinel_tid_t NcpSpinel::GetNextTid(void)
Expand Down Expand Up @@ -513,19 +599,19 @@ void NcpSpinel::FreeTidTableItem(spinel_tid_t aTid)
mWaitingKeyTable[aTid] = SPINEL_PROP_LAST_STATUS;
}

otError NcpSpinel::SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
otError NcpSpinel::SendCommand(spinel_command_t aCmd, spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
{
otError error = OT_ERROR_NONE;
spinel_tid_t tid = GetNextTid();
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(mIid) | tid;

VerifyOrExit(tid != 0, error = OT_ERROR_BUSY);
SuccessOrExit(error = mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, aKey));
SuccessOrExit(error = mEncoder.BeginFrame(header, aCmd, aKey));
SuccessOrExit(error = aEncodingFunc());
SuccessOrExit(error = mEncoder.EndFrame());
SuccessOrExit(error = SendEncodedFrame());

mCmdTable[tid] = SPINEL_CMD_PROP_VALUE_SET;
mCmdTable[tid] = aCmd;
mWaitingKeyTable[tid] = aKey;
exit:
if (error != OT_ERROR_NONE)
Expand All @@ -535,6 +621,21 @@ otError NcpSpinel::SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEnco
return error;
}

otError NcpSpinel::SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
{
return SendCommand(SPINEL_CMD_PROP_VALUE_SET, aKey, aEncodingFunc);
}

otError NcpSpinel::InsertProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
{
return SendCommand(SPINEL_CMD_PROP_VALUE_INSERT, aKey, aEncodingFunc);
}

otError NcpSpinel::RemoveProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
{
return SendCommand(SPINEL_CMD_PROP_VALUE_REMOVE, aKey, aEncodingFunc);
}

otError NcpSpinel::SendEncodedFrame(void)
{
otError error = OT_ERROR_NONE;
Expand Down
14 changes: 14 additions & 0 deletions src/ncp/ncp_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,14 +286,28 @@ class NcpSpinel : public Netif::Dependencies
spinel_prop_key_t aKey,
const uint8_t *aData,
uint16_t aLength);
otbrError HandleResponseForPropInsert(spinel_tid_t aTid,
spinel_command_t aCmd,
spinel_prop_key_t aKey,
const uint8_t *aData,
uint16_t aLength);
otbrError HandleResponseForPropRemove(spinel_tid_t aTid,
spinel_command_t aCmd,
spinel_prop_key_t aKey,
const uint8_t *aData,
uint16_t aLength);

otbrError Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded) override;

spinel_tid_t GetNextTid(void);
void FreeTidTableItem(spinel_tid_t aTid);

using EncodingFunc = std::function<otError(void)>;
otError SendCommand(spinel_command_t aCmd, spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);
otError SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);
otError InsertProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);
otError RemoveProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);

otError SendEncodedFrame(void);

otError ParseIp6AddressTable(const uint8_t *aBuf, uint16_t aLength, std::vector<Ip6AddressInfo> &aAddressTable);
Expand Down
26 changes: 23 additions & 3 deletions src/ncp/posix/netif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,12 +453,32 @@ void Netif::ProcessMldEvent(void)
case kIcmpv6Mldv2ModeIsExcludeType:
error = OTBR_ERROR_NONE;
break;
///< Only update subscription on NCP when the target multicast address is not in `mIp6MulticastAddresses`.
///< This indicates that this is the first time the multicast address subscription needs to be updated.
case kIcmpv6Mldv2RecordChangeToIncludeType:
error = (record->mNumSources == 0) ? mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ false)
: OTBR_ERROR_NONE;
if (record->mNumSources == 0)
{
if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), Ip6Address(address)) !=
mIp6MulticastAddresses.end())
{
error = mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ false);
}
else
{
error = OTBR_ERROR_NONE;
}
}
break;
case kIcmpv6Mldv2RecordChangeToExcludeType:
error = mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ true);
if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), Ip6Address(address)) ==
mIp6MulticastAddresses.end())
{
error = mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ true);
}
else
{
error = OTBR_ERROR_NONE;
}
break;
}

Expand Down

0 comments on commit dd261f0

Please sign in to comment.