[p2p] add unlink API to tear down the P2P link (#11904)

This commit is contained in:
Zhanglong Xia
2025-09-09 05:15:09 +08:00
committed by GitHub
parent d7d26f10b1
commit db7f037f73
12 changed files with 291 additions and 31 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (534)
#define OPENTHREAD_API_VERSION (535)
/**
* @addtogroup api-instance
+24
View File
@@ -91,6 +91,30 @@ otError otP2pWakeupAndLink(otInstance *aInstance,
otP2pLinkDoneCallback aCallback,
void *aContext);
/**
* Notifies the caller that the P2P link tear down process has ended.
*
* @param[in] aContext A pointer to application-specific context.
*/
typedef void (*otP2pUnlinkDoneCallback)(void *aContext);
/**
* Tears down the P2P link specified by the Extended Address.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aExtAddress A pointer to the P2P peer's Extended Address.
* @param[in] aCallback A pointer to function that is called when the P2P link tear down process has ended.
* @param[in] aContext A pointer to callback application-specific context.
*
* @retval OT_ERROR_NONE Successfully started to tear down the P2P link.
* @retval OT_ERROR_BUSY Tearing down or establishing a P2P link process is in progress.
* @retval OT_ERROR_NOT_FOUND The P2P link identified by the @p aExtAddress was not found.
*/
otError otP2pUnlink(otInstance *aInstance,
const otExtAddress *aExtAddress,
otP2pUnlinkDoneCallback aCallback,
void *aContext);
/**
* Defines events of the P2P link.
*/
+11
View File
@@ -3125,6 +3125,17 @@ Wakes up the peer identified by the extended address and establishes a peer-to-p
Done
```
### p2p unlink \<extaddress\>
Tears down the P2P link identified by the extended address.
`OPENTHREAD_CONFIG_P2P_ENABLE` is required.
```bash
> p2p unlink dead00beef00cafe
Done
```
### panid
Get the IEEE 802.15.4 PAN ID value.
+37 -12
View File
@@ -8088,22 +8088,43 @@ exit:
#endif // OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE
#if OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
#if OPENTHREAD_CONFIG_P2P_ENABLE
template <> otError Interpreter::Process<Cmd("p2p")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0] == "link")
if (aArgs[0] == "unlink")
{
otExtAddress extAddress;
/**
* @cli p2p unlink
* @code
* p2p unlink dead00beef00cafe
* Done
* @endcode
* @cparam p2p unlink @ca{extended-address}
* @par
* `OPENTHREAD_CONFIG_P2P_ENABLE` is required.
* @par
* Tears down the P2P link identified by the extended address.
*/
SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddress.m8));
SuccessOrExit(error = otP2pUnlink(GetInstancePtr(), &extAddress, HandleP2pUnlinkDone, this));
error = OT_ERROR_PENDING;
}
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
else if (aArgs[0] == "link")
{
otP2pRequest p2pRequest;
/**
* @cli link
* @cli p2p link
* @code
* link extaddr dead00beef00cafe
* p2p link extaddr dead00beef00cafe
* Done
* @endcode
* @cparam link extaddr @ca{extended-address}
* @cparam p2p link extaddr @ca{extended-address}
* @par
* `OPENTHREAD_CONFIG_P2P_ENABLE` and `OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE` are required.
* @par
@@ -8120,9 +8141,10 @@ template <> otError Interpreter::Process<Cmd("p2p")>(Arg aArgs[])
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
SuccessOrExit(error = otP2pWakeupAndLink(GetInstancePtr(), &p2pRequest, HandleP2pLinkedResult, this));
SuccessOrExit(error = otP2pWakeupAndLink(GetInstancePtr(), &p2pRequest, HandleP2pLinkDone, this));
error = OT_ERROR_PENDING;
}
#endif
else
{
error = OT_ERROR_INVALID_ARGS;
@@ -8132,13 +8154,16 @@ exit:
return error;
}
void Interpreter::HandleP2pLinkedResult(void *aContext)
{
static_cast<Interpreter *>(aContext)->HandleP2pLinkedResult();
}
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
void Interpreter::HandleP2pLinkDone(void *aContext) { static_cast<Interpreter *>(aContext)->HandleP2pLinkDone(); }
void Interpreter::HandleP2pLinkedResult(void) { OutputResult(OT_ERROR_NONE); }
#endif // OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
void Interpreter::HandleP2pLinkDone(void) { OutputResult(OT_ERROR_NONE); }
#endif
void Interpreter::HandleP2pUnlinkDone(void *aContext) { static_cast<Interpreter *>(aContext)->HandleP2pUnlinkDone(); }
void Interpreter::HandleP2pUnlinkDone(void) { OutputResult(OT_ERROR_NONE); }
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
template <> otError Interpreter::Process<Cmd("wakeup")>(Arg aArgs[])
+8 -3
View File
@@ -310,9 +310,14 @@ private:
static void HandleIp6Receive(otMessage *aMessage, void *aContext);
#endif
#if OPENTHREAD_CONFIG_P2P_ENABLE && OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
static void HandleP2pLinkedResult(void *aContext);
void HandleP2pLinkedResult(void);
#if OPENTHREAD_CONFIG_P2P_ENABLE
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
static void HandleP2pLinkDone(void *aContext);
void HandleP2pLinkDone(void);
#endif
static void HandleP2pUnlinkDone(void *aContext);
void HandleP2pUnlinkDone(void);
#endif
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
+8
View File
@@ -53,4 +53,12 @@ void otP2pSetEventCallback(otInstance *aInstance, otP2pEventCallback aCallback,
{
AsCoreType(aInstance).Get<Mle::Mle>().P2pSetEventCallback(aCallback, aContext);
}
otError otP2pUnlink(otInstance *aInstance,
const otExtAddress *aExtAddress,
otP2pUnlinkDoneCallback aCallback,
void *aContext)
{
return AsCoreType(aInstance).Get<Mle::Mle>().P2pUnlink(AsCoreType(aExtAddress), aCallback, aContext);
}
#endif
+6
View File
@@ -1780,6 +1780,10 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
mP2p.HandleP2pLinkAcceptAndRequest(rxInfo);
break;
#endif
case kCommandP2pLinkTearDown:
mP2p.HandleP2pLinkTearDown(rxInfo);
break;
#endif // OPENTHREAD_CONFIG_P2P_ENABLE
default:
@@ -2895,6 +2899,7 @@ const char *Mle::MessageTypeToString(MessageType aType)
"P2P Link Request", // (32) kTypeP2pLinkRequest
"P2P Link Accept and Request", // (33) kTypeP2pLinkAcceptAndRequest
"P2P Link Accept", // (34) kTypeP2pLinkAccept
"P2P Link Tear Down", // (35) kTypeP2pLinkTearDown
#endif
};
@@ -2943,6 +2948,7 @@ const char *Mle::MessageTypeToString(MessageType aType)
ValidateNextEnum(kTypeP2pLinkRequest);
ValidateNextEnum(kTypeP2pLinkAcceptAndRequest);
ValidateNextEnum(kTypeP2pLinkAccept);
ValidateNextEnum(kTypeP2pLinkTearDown);
#endif
};
+38 -10
View File
@@ -135,8 +135,10 @@ class Mle : public InstanceLocator, private NonCopyable
public:
typedef otDetachGracefullyCallback DetachCallback; ///< Callback to signal end of graceful detach.
typedef otP2pLinkDoneCallback P2pLinkDoneCallback; ///< Callback to inform the result of establishing P2P links.
typedef otP2pEventCallback P2pEventCallback; ///< Callback to signal events of the P2P link.
typedef otWakeupCallback WakeupCallback; ///< Callback to communicate the result of waking a Wake-up End Device
typedef otP2pUnlinkDoneCallback
P2pUnlinkDoneCallback; ///< Callback to inform the result of tearing down the P2P link.
typedef otP2pEventCallback P2pEventCallback; ///< Callback to signal events of the P2P link.
typedef otWakeupCallback WakeupCallback; ///< Callback to communicate the result of waking a Wake-up End Device.
/**
* Initializes the MLE object.
@@ -1186,6 +1188,22 @@ public:
}
#endif
/**
* Tears down the P2P link specified by the Extended Address.
*
* @param[in] aExtAddress A constant reference to the P2P peer's Extended Address.
* @param[in] aCallback A pointer to function that is called when the P2P link tear down process has ended.
* @param[in] aContext A pointer to callback application-specific context.
*
* @retval OT_ERROR_NONE Successfully started to tear down the P2P link.
* @retval OT_ERROR_BUSY Tearing down or establishing a P2P link process is in progress.
* @retval OT_ERROR_NOT_FOUND The P2P link identified by the @p aExtAddress was not found.
*/
Error P2pUnlink(const Mac::ExtAddress &aExtAddress, P2pUnlinkDoneCallback aCallback, void *aContext)
{
return mP2p.Unlink(aExtAddress, aCallback, aContext);
}
/**
* Sets the callback function to notify event changes of P2P links.
*
@@ -1473,6 +1491,7 @@ private:
kTypeP2pLinkRequest,
kTypeP2pLinkAcceptAndRequest,
kTypeP2pLinkAccept,
kTypeP2pLinkTearDown,
#endif
};
@@ -2170,8 +2189,10 @@ private:
void HandleP2pLinkAcceptAndRequest(RxInfo &aRxInfo);
#endif
void SetEventCallback(P2pEventCallback aCallback, void *aContext);
void HandleLinkTimer(void);
Error Unlink(const Mac::ExtAddress &aExtAddress, P2pUnlinkDoneCallback aCallback, void *aContext);
void HandleP2pLinkTearDown(RxInfo &aRxInfo);
void SetEventCallback(P2pEventCallback aCallback, void *aContext);
void HandleLinkTimer(void);
private:
static constexpr uint16_t kWakeupMaxDuration = OPENTHREAD_CONFIG_WAKEUP_MAX_DURATION;
@@ -2185,6 +2206,7 @@ private:
kStateWaitingLinkAccept,
kStateAttachDelay,
kStateWaitingLinkAcceptAndRequest,
kStateTearingDown,
};
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
@@ -2196,19 +2218,25 @@ private:
Error SendP2pLinkAcceptAndRequest(const LinkAcceptInfo &aInfo);
#endif
static void HandleLinkTearDownTxDone(const otMessage *aMessage, otError aError, void *aContext);
void HandleLinkTearDownTxDone(const Message &aMessage);
Error SendP2pLinkAcceptVariant(const LinkAcceptInfo &aInfo, bool aIsLinkAcceptorRequest);
void HandleP2pLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType);
void SetWakeupListenerEnabled(void);
void ClearPeersInLinkRequestState(void);
Error SendLinkTearDown(Peer &aPeer);
void PeerUnlinked(Peer &aPeer);
using P2pLinkTimer = TimerMicroIn<Mle, &Mle::HandleP2pLinkTimer>;
State mState;
PeerTable mPeerTable;
P2pLinkTimer mTimer;
Callback<P2pLinkDoneCallback> mLinkedCallback;
Callback<P2pEventCallback> mEventCallback;
Peer *mPeer;
State mState;
PeerTable mPeerTable;
P2pLinkTimer mTimer;
Callback<P2pLinkDoneCallback> mLinkDoneCallback;
Callback<P2pUnlinkDoneCallback> mUnlinkDoneCallback;
Callback<P2pEventCallback> mEventCallback;
Peer *mPeer;
};
#endif
+110 -4
View File
@@ -53,7 +53,8 @@ Mle::P2p::P2p(Instance &aInstance)
, mState(kStateIdle)
, mPeerTable(aInstance)
, mTimer(aInstance)
, mLinkedCallback()
, mLinkDoneCallback()
, mUnlinkDoneCallback()
, mEventCallback()
, mPeer(nullptr)
{
@@ -77,7 +78,7 @@ Error Mle::P2p::WakeupAndLink(const P2pRequest &aP2pRequest, P2pLinkDoneCallback
error = Get<WakeupTxScheduler>().WakeUp(aP2pRequest.GetWakeupRequest(), kWakeupTxInterval, kWakeupMaxDuration));
mState = kStateWakingUp;
mLinkedCallback.Set(aCallback, aContext);
mLinkDoneCallback.Set(aCallback, aContext);
mTimer.FireAt(Get<WakeupTxScheduler>().GetTxEndTime() + Get<WakeupTxScheduler>().GetConnectionWindowUs());
exit:
@@ -333,7 +334,7 @@ void Mle::P2p::HandleP2pLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageT
// All P2P links have been established.
mState = kStateIdle;
mTimer.Stop();
mLinkedCallback.InvokeAndClearIfSet();
mLinkDoneCallback.InvokeAndClearIfSet();
}
}
@@ -341,6 +342,111 @@ exit:
LogProcessError(aMessageType, error);
}
Error Mle::P2p::Unlink(const Mac::ExtAddress &aExtAddress, P2pUnlinkDoneCallback aCallback, void *aContext)
{
Error error = kErrorNone;
Peer *peer;
VerifyOrExit(mState == kStateIdle, error = kErrorBusy);
VerifyOrExit((peer = mPeerTable.FindPeer(aExtAddress, Peer::kInStateValid)) != nullptr, error = kErrorNotFound);
SuccessOrExit(error = SendLinkTearDown(*peer));
mState = kStateTearingDown;
mUnlinkDoneCallback.Set(aCallback, aContext);
exit:
return error;
}
Error Mle::P2p::SendLinkTearDown(Peer &aPeer)
{
Error error = kErrorNone;
TxMessage *message;
Ip6::Address destination;
aPeer.GetLinkLocalIp6Address(destination);
VerifyOrExit((message = Get<Mle>().NewMleMessage(kCommandP2pLinkTearDown)) != nullptr, error = kErrorNoBufs);
message->RegisterTxCallback(HandleLinkTearDownTxDone, this);
SuccessOrExit(error = message->SendTo(destination));
Log(kMessageSend, kTypeP2pLinkTearDown, destination);
exit:
FreeMessageOnError(message, error);
return error;
}
void Mle::P2p::HandleLinkTearDownTxDone(const otMessage *aMessage, otError aError, void *aContext)
{
OT_UNUSED_VARIABLE(aError);
static_cast<Mle::P2p *>(aContext)->HandleLinkTearDownTxDone(AsCoreType(aMessage));
}
void Mle::P2p::HandleLinkTearDownTxDone(const Message &aMessage)
{
Ip6::Header ip6Header;
Mac::ExtAddress extAddress;
Peer *peer;
SuccessOrExit(aMessage.Read(0, ip6Header));
VerifyOrExit(ip6Header.GetDestination().IsLinkLocalUnicast());
extAddress.SetFromIid(ip6Header.GetDestination().GetIid());
peer = mPeerTable.FindPeer(extAddress, Peer::kInStateValid);
if (peer == nullptr)
{
// Peer may have been removed if we received a tear down from it. In this case, we can consider the unlink done.
mState = kStateIdle;
mUnlinkDoneCallback.InvokeAndClearIfSet();
ExitNow();
}
if (!aMessage.GetTxSuccess() && (peer->GetTearDownCount() < Peer::kMaxRetransmitLinkTearDowns))
{
peer->IncrementTearDownCount();
if (SendLinkTearDown(*peer) == kErrorNone)
{
ExitNow();
}
}
PeerUnlinked(*peer);
mUnlinkDoneCallback.InvokeAndClearIfSet();
exit:
return;
}
void Mle::P2p::PeerUnlinked(Peer &aPeer)
{
aPeer.SetState(Neighbor::kStateInvalid);
if (mState == kStateTearingDown)
{
mState = kStateIdle;
}
mEventCallback.InvokeIfSet(OT_P2P_EVENT_UNLINKED, &aPeer.GetExtAddress());
}
void Mle::P2p::HandleP2pLinkTearDown(RxInfo &aRxInfo)
{
Peer *peer;
Mac::ExtAddress extAddress;
Log(kMessageReceive, kTypeP2pLinkTearDown, aRxInfo.mMessageInfo.GetPeerAddr());
VerifyOrExit(aRxInfo.mMessageInfo.GetPeerAddr().IsLinkLocalUnicast());
extAddress.SetFromIid(aRxInfo.mMessageInfo.GetPeerAddr().GetIid());
VerifyOrExit((peer = mPeerTable.FindPeer(extAddress, Peer::kInStateValid)) != nullptr);
Get<Mle>().ProcessKeySequence(aRxInfo);
PeerUnlinked(*peer);
exit:
return;
}
void Mle::P2p::HandleLinkTimer(void)
{
switch (mState)
@@ -356,7 +462,7 @@ void Mle::P2p::HandleLinkTimer(void)
mState = kStateIdle;
ClearPeersInLinkRequestState();
mLinkedCallback.InvokeAndClearIfSet();
mLinkDoneCallback.InvokeAndClearIfSet();
}
break;
#endif
+1
View File
@@ -160,6 +160,7 @@ enum Command : uint8_t
kCommandP2pLinkRequest = 100, ///< P2P Link Request command
kCommandP2pLinkAccept = 101, ///< P2P Link Accept command
kCommandP2pLinkAcceptAndRequest = 102, ///< P2P Link Accept And Request command
kCommandP2pLinkTearDown = 103, ///< P2P Link Tear Down command
};
/**
+27 -1
View File
@@ -48,12 +48,21 @@ namespace ot {
class Peer : public CslNeighbor
{
public:
/**
* Max number of re-transmitted the P2P link tear down messages.
*/
static constexpr uint8_t kMaxRetransmitLinkTearDowns = 4;
/**
* Initializes the `Peer` object.
*
* @param[in] aInstance The OpenThread instance.
*/
void Init(Instance &aInstance) { Neighbor::Init(aInstance); }
void Init(Instance &aInstance)
{
Neighbor::Init(aInstance);
mTearDownCount = 0;
}
/**
* Clears the peer entry.
@@ -86,8 +95,25 @@ public:
*/
const Mle::TxChallenge &GetChallenge(void) const { return mAttachChallenge; }
/**
* Increments the count of re-transmitted link tear down messages.
*/
void IncrementTearDownCount(void) { mTearDownCount++; }
/**
* Resets the count of re-transmitted link tear down messages to zero.
*/
void ResetTearDownCount(void) { mTearDownCount = 0; }
/**
* Returns the count of re-transmitted link tear down messages.
*/
uint8_t GetTearDownCount(void) const { return mTearDownCount; }
private:
Mle::TxChallenge mAttachChallenge;
uint8_t mTearDownCount : 3; // The count of re-transmitted link tear down messages.
};
} // namespace ot
@@ -214,4 +214,24 @@ for {set i 1} {$i <= 5} {incr i} {
expect "28 bytes from $wc1_link_local_addr: icmp_seq=$i"
}
send_user "\n\n>>> WC1 tears down the P2P link with WL1\n"
switch_node $WC1
send "p2p unlink $WL1_EXT_ADDRESS\n"
expect_line "Done"
send_user "\n\n>>> WC2 tears down the P2P link with WL1\n"
switch_node $WC2
send "p2p unlink $WL1_EXT_ADDRESS\n"
expect_line "Done"
send_user "\n\n>>> WL2 tears down the P2P link with WC1\n"
switch_node $WL2
send "p2p unlink $WC1_EXT_ADDRESS\n"
expect_line "Done"
sleep 1
dispose_all