Add callback to indicate when joiner operation completes. (#1094)

This commit is contained in:
Jonathan Hui
2016-12-27 08:06:18 -08:00
committed by GitHub
parent 28c049f2ce
commit 64d49153bd
18 changed files with 247 additions and 48 deletions
+2 -1
View File
@@ -40,7 +40,6 @@ CPPFLAGS_COMMON = \
$(NULL)
LDADD_COMMON = \
$(top_builddir)/src/cli/libopenthread-cli.a \
$(NULL)
LDFLAGS_COMMON = \
@@ -84,6 +83,7 @@ ot_cli_ftd_CPPFLAGS = \
$(NULL)
ot_cli_ftd_LDADD = \
$(top_builddir)/src/cli/libopenthread-cli.a \
$(top_builddir)/src/core/libopenthread-ftd.a \
$(LDADD_COMMON) \
$(NULL)
@@ -101,6 +101,7 @@ ot_cli_mtd_CPPFLAGS = \
$(NULL)
ot_cli_mtd_LDADD = \
$(top_builddir)/src/cli/libopenthread-cli.a \
$(top_builddir)/src/core/libopenthread-mtd.a \
$(LDADD_COMMON) \
$(NULL)
+3 -1
View File
@@ -3490,7 +3490,9 @@ OTCALL
otJoinerStart(
_In_ otInstance *aInstance,
const char *aPSKd,
const char *aProvisioningUrl
const char *aProvisioningUrl,
_In_ otJoinerCallback aCallback,
_In_ void *aCallbackContext
)
{
if (aInstance == nullptr || aPSKd == nullptr) return kThreadError_InvalidArgs;
+8 -2
View File
@@ -5270,8 +5270,14 @@ otLwfIoCtl_otJoinerStart(
if (InBufferLength >= sizeof(otCommissionConfig))
{
otCommissionConfig *aConfig = (otCommissionConfig*)InBuffer;
status = ThreadErrorToNtstatus(otJoinerStart(
pFilter->otCtx, (const char*)aConfig->PSKd, (const char*)aConfig->ProvisioningUrl));
status = ThreadErrorToNtstatus(
otJoinerStart(
pFilter->otCtx,
(const char*)aConfig->PSKd,
(const char*)aConfig->ProvisioningUrl,
NULL, // TODO: handle the joiner completion callback
NULL)
);
}
return status;
@@ -949,7 +949,8 @@ OTNODEAPI int32_t OTCALL otNodeJoinerStart(otNode* aNode, const char *aPSKd, con
otLogFuncEntryMsg("[%d] %s %s", aNode->mId, aPSKd, aProvisioningUrl);
printf("%d: joiner start %s %s\r\n", aNode->mId, aPSKd, aProvisioningUrl);
auto error = otJoinerStart(aNode->mInstance, aPSKd, aProvisioningUrl);
// TODO: handle the joiner completion callback
auto error = otJoinerStart(aNode->mInstance, aPSKd, aProvisioningUrl, NULL, NULL);
otLogFuncExit();
return error;
+16 -1
View File
@@ -48,18 +48,33 @@ extern "C" {
*
*/
/**
* This function pointer is called to notify the completion of a join operation.
*
* @param[in] aError kThreadError_None if the join process succeeded.
* kThreadError_Security if the join process failed due to security credentials.
* kThreadError_NotFound if no joinable network was discovered.
* kThreadError_ResponseTimeout if a response timed out.
* @param[in] aContext A pointer to application-specific context.
*
*/
typedef void (OTCALL *otJoinerCallback)(ThreadError aError, void *aContext);
/**
* This function enables the Thread Joiner role.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aPSKd A pointer to the PSKd.
* @param[in] aProvisioningUrl A pointer to the Provisioning URL (may be NULL).
* @param[in] aCallback A pointer to a function that is called when the join operation completes.
* @param[in] aContext A pointer to application-specific context.
*
* @retval kThreadError_None Successfully started the Commissioner role.
* @retval kThreadError_InvalidArgs @p aPSKd or @p aProvisioningUrl is invalid.
*
*/
OTAPI ThreadError OTCALL otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl);
OTAPI ThreadError OTCALL otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl,
otJoinerCallback aCallback, void *aContext);
/**
* This function disables the Thread Joiner role.
+20 -1
View File
@@ -2438,7 +2438,7 @@ void Interpreter::ProcessJoiner(int argc, char *argv[])
const char *provisioningUrl;
VerifyOrExit(argc > 1, error = kThreadError_Parse);
provisioningUrl = (argc > 2) ? argv[2] : NULL;
otJoinerStart(mInstance, argv[1], provisioningUrl);
otJoinerStart(mInstance, argv[1], provisioningUrl, &Interpreter::s_HandleJoinerCallback, this);
}
else if (strcmp(argv[0], "stop") == 0)
{
@@ -2451,6 +2451,25 @@ exit:
#endif // OPENTHREAD_ENABLE_JOINER
void Interpreter::s_HandleJoinerCallback(ThreadError aError, void *aContext)
{
static_cast<Interpreter *>(aContext)->HandleJoinerCallback(aError);
}
void Interpreter::HandleJoinerCallback(ThreadError aError)
{
switch (aError)
{
case kThreadError_None:
sServer->OutputFormat("Join success\r\n");
break;
default:
sServer->OutputFormat("Join failed [%s]\r\n", otThreadErrorToString(aError));
break;
}
}
void Interpreter::ProcessJoinerPort(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
+2
View File
@@ -225,6 +225,7 @@ private:
void *aContext);
static void s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext);
static void s_HandleDiagnosticGetResponse(otMessage aMessage, const otMessageInfo *aMessageInfo, void *aContext);
static void s_HandleJoinerCallback(ThreadError aError, void *aContext);
void HandleEchoResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandlePingTimer();
@@ -234,6 +235,7 @@ private:
void HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength);
void HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask);
void HandleDiagnosticGetResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandleJoinerCallback(ThreadError aError);
static const struct Command sCommands[];
+15 -8
View File
@@ -73,7 +73,8 @@ ThreadError SecureClient::Connect(const Ip6::MessageInfo &aMessageInfo, Connecte
mConnectedCallback = aCallback;
mContext = aContext;
return mNetif.GetDtls().Start(true, &SecureClient::HandleDtlsReceive, &SecureClient::HandleDtlsSend, this);
return mNetif.GetDtls().Start(true, &SecureClient::HandleDtlsConnected, &SecureClient::HandleDtlsReceive,
&SecureClient::HandleDtlsSend, this);
}
bool SecureClient::IsConnectionActive(void)
@@ -136,17 +137,23 @@ void SecureClient::Receive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
mNetif.GetDtls().Receive(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset());
if ((IsConnected()) && (mConnectedCallback != NULL))
{
mConnectedCallback(mContext);
mConnectedCallback = NULL;
mContext = NULL;
}
exit:
otLogFuncExit();
}
void SecureClient::HandleDtlsConnected(void *aContext, bool aConnected)
{
return static_cast<SecureClient *>(aContext)->HandleDtlsConnected(aConnected);
}
void SecureClient::HandleDtlsConnected(bool aConnected)
{
if (mConnectedCallback != NULL)
{
mConnectedCallback(aConnected, mContext);
}
}
void SecureClient::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
{
return static_cast<SecureClient *>(aContext)->HandleDtlsReceive(aBuf, aLength);
+6 -2
View File
@@ -49,10 +49,11 @@ public:
/**
* This function pointer is called once DTLS connection is established.
*
* @param[in] aContext A pointer to arbitrary context information.
* @param[in] aConnected TRUE if a connection was established, FALSE otherwise.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
typedef void (*ConnectedCallback)(void *aContext);
typedef void (*ConnectedCallback)(bool aConnected, void *aContext);
/**
* This constructor initializes the object.
@@ -140,6 +141,9 @@ private:
static void Receive(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void Receive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleDtlsConnected(void *aContext, bool aConnected);
void HandleDtlsConnected(bool aConnected);
static void HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength);
void HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength);
+11 -1
View File
@@ -118,7 +118,7 @@ void SecureServer::Receive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
mPeerAddress.SetPeerAddr(aMessageInfo.GetPeerAddr());
mPeerAddress.SetPeerPort(aMessageInfo.GetPeerPort());
mNetif.GetDtls().Start(false, HandleDtlsReceive, HandleDtlsSend, this);
mNetif.GetDtls().Start(false, HandleDtlsConnected, HandleDtlsReceive, HandleDtlsSend, this);
}
else
{
@@ -140,6 +140,16 @@ ThreadError SecureServer::SetPsk(const uint8_t *aPsk, uint8_t aPskLength)
return mNetif.GetDtls().SetPsk(aPsk, aPskLength);
}
void SecureServer::HandleDtlsConnected(void *aContext, bool aConnected)
{
return static_cast<SecureServer *>(aContext)->HandleDtlsConnected(aConnected);
}
void SecureServer::HandleDtlsConnected(bool aConnected)
{
(void)aConnected;
}
void SecureServer::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
{
return static_cast<SecureServer *>(aContext)->HandleDtlsReceive(aBuf, aLength);
+3
View File
@@ -120,6 +120,9 @@ private:
static void Receive(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleDtlsConnected(void *aContext, bool aConnected);
void HandleDtlsConnected(bool aConnected);
static void HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength);
void HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength);
+1 -1
View File
@@ -66,8 +66,8 @@ Commissioner::Commissioner(ThreadNetif &aThreadNetif):
mState(kStateDisabled),
mJoinerPort(0),
mJoinerRloc(0),
mSessionId(0),
mTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleTimer, this),
mSessionId(0),
mTransmitAttempts(0),
mSendKek(false),
mRelayReceive(OPENTHREAD_URI_RELAY_RX, &Commissioner::HandleRelayReceive, this),
+1 -1
View File
@@ -248,8 +248,8 @@ private:
uint16_t mJoinerPort;
uint16_t mJoinerRloc;
uint16_t mSessionId;
Timer mTimer;
uint16_t mSessionId;
uint8_t mTransmitAttempts;
bool mSendKek;
+23 -8
View File
@@ -56,6 +56,7 @@ Dtls::Dtls(ThreadNetif &aNetif):
mReceiveMessage(NULL),
mReceiveOffset(0),
mReceiveLength(0),
mConnectedHandler(NULL),
mReceiveHandler(NULL),
mSendHandler(NULL),
mContext(NULL),
@@ -71,11 +72,13 @@ Dtls::Dtls(ThreadNetif &aNetif):
mProvisioningUrl.Init();
}
ThreadError Dtls::Start(bool aClient, ReceiveHandler aReceiveHandler, SendHandler aSendHandler, void *aContext)
ThreadError Dtls::Start(bool aClient, ConnectedHandler aConnectedHandler, ReceiveHandler aReceiveHandler,
SendHandler aSendHandler, void *aContext)
{
static const int ciphersuites[2] = {0xC0FF, 0}; // EC-JPAKE cipher suite
int rval;
mConnectedHandler = aConnectedHandler;
mReceiveHandler = aReceiveHandler;
mSendHandler = aSendHandler;
mContext = aContext;
@@ -142,15 +145,22 @@ ThreadError Dtls::Stop(void)
void Dtls::Close(void)
{
if (mStarted)
VerifyOrExit(mStarted,);
mStarted = false;
mbedtls_ssl_free(&mSsl);
mbedtls_ssl_config_free(&mConf);
mbedtls_ctr_drbg_free(&mCtrDrbg);
mbedtls_entropy_free(&mEntropy);
mbedtls_ssl_cookie_free(&mCookieCtx);
if (mConnectedHandler != NULL)
{
mStarted = false;
mbedtls_ssl_free(&mSsl);
mbedtls_ssl_config_free(&mConf);
mbedtls_ctr_drbg_free(&mCtrDrbg);
mbedtls_entropy_free(&mEntropy);
mbedtls_ssl_cookie_free(&mCookieCtx);
mConnectedHandler(mContext, false);
}
exit:
return;
}
bool Dtls::IsStarted(void)
@@ -367,6 +377,11 @@ void Dtls::Process(void)
if (mSsl.state != MBEDTLS_SSL_HANDSHAKE_OVER)
{
rval = mbedtls_ssl_handshake(&mSsl);
if ((mSsl.state == MBEDTLS_SSL_HANDSHAKE_OVER) && (mConnectedHandler != NULL))
{
mConnectedHandler(mContext, true);
}
}
else
{
+18 -6
View File
@@ -70,6 +70,15 @@ public:
*/
Dtls(ThreadNetif &aNetif);
/**
* This function pointer is called when a connection is established or torn down.
*
* @param[in] aContext A pointer to application-specific context.
* @param[in] aConnected TRUE if a connection was established, FALSE otherwise.
*
*/
typedef void (*ConnectedHandler)(void *aContext, bool aConnected);
/**
* This function pointer is called when data is received from the DTLS session.
*
@@ -93,15 +102,17 @@ public:
/**
* This method starts the DTLS service.
*
* @param[in] aClient TRUE if operating as a client, FALSE if operating as a server.
* @param[in] aReceiveHandler A pointer to the receive handler.
* @param[in] aSendHandler A pointer to the send handler.
* @param[in] aContext A pointer to application-specific context.
* @param[in] aClient TRUE if operating as a client, FALSE if operating as a server.
* @param[in] aConnectedHandler A pointer to the connected handler.
* @param[in] aReceiveHandler A pointer to the receive handler.
* @param[in] aSendHandler A pointer to the send handler.
* @param[in] aContext A pointer to application-specific context.
*
* @retval kThreadError_None Successfully started the DTLS service.
* @retval kThreadError_None Successfully started the DTLS service.
*
*/
ThreadError Start(bool aClient, ReceiveHandler aReceiveHandler, SendHandler aSendHandler, void *aContext);
ThreadError Start(bool aClient, ConnectedHandler aConnectedHandler, ReceiveHandler aReceiveHandler,
SendHandler aSendHandler, void *aContext);
/**
* This method stops the DTLS service.
@@ -227,6 +238,7 @@ private:
uint16_t mReceiveOffset;
uint16_t mReceiveLength;
ConnectedHandler mConnectedHandler;
ReceiveHandler mReceiveHandler;
SendHandler mSendHandler;
void *mContext;
+91 -10
View File
@@ -43,6 +43,7 @@
#include <common/code_utils.hpp>
#include <common/crc16.hpp>
#include <common/debug.hpp>
#include <common/encoding.hpp>
#include <common/logging.hpp>
#include <mac/mac_frame.hpp>
@@ -59,6 +60,9 @@ namespace Thread {
namespace MeshCoP {
Joiner::Joiner(ThreadNetif &aNetif):
mState(kStateIdle),
mCallback(NULL),
mContext(NULL),
mJoinerRouterChannel(0),
mJoinerRouterPanId(0),
mJoinerUdpPort(0),
@@ -71,13 +75,15 @@ Joiner::Joiner(ThreadNetif &aNetif):
mCoapServer.AddResource(mJoinerEntrust);
}
ThreadError Joiner::Start(const char *aPSKd, const char *aProvisioningUrl)
ThreadError Joiner::Start(const char *aPSKd, const char *aProvisioningUrl, otJoinerCallback aCallback, void *aContext)
{
ThreadError error;
Mac::ExtAddress extAddress;
otLogFuncEntry();
VerifyOrExit(mState == kStateIdle, error = kThreadError_Busy);
// use extended address based on factory-assigned IEEE EUI-64
mNetif.GetMac().GetHashMacAddress(&extAddress);
mNetif.GetMac().SetExtAddress(extAddress);
@@ -90,6 +96,10 @@ ThreadError Joiner::Start(const char *aPSKd, const char *aProvisioningUrl)
mJoinerRouterPanId = Mac::kPanIdBroadcast;
SuccessOrExit(error = mNetif.GetMle().Discover(0, 0, mNetif.GetMac().GetPanId(), HandleDiscoverResult, this));
mCallback = aCallback;
mContext = aContext;
mState = kStateDiscover;
exit:
otLogFuncExitErr(error);
return error;
@@ -115,6 +125,18 @@ void Joiner::Close(void)
otLogFuncExit();
}
void Joiner::Complete(ThreadError aError)
{
mState = kStateIdle;
if (mCallback)
{
otJoinerCallback callback = mCallback;
mCallback = NULL;
callback(aError, mContext);
}
}
void Joiner::HandleDiscoverResult(otActiveScanResult *aResult, void *aContext)
{
static_cast<Joiner *>(aContext)->HandleDiscoverResult(aResult);
@@ -173,14 +195,43 @@ void Joiner::HandleDiscoverResult(otActiveScanResult *aResult)
messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
mSecureCoapClient.Connect(messageInfo, Joiner::HandleSecureCoapClientConnect, this);
mState = kStateConnect;
}
else
{
otLogDebgMeshCoP("No joinable network found");
Complete(kThreadError_NotFound);
}
otLogFuncExit();
}
void Joiner::HandleSecureCoapClientConnect(void *aContext)
void Joiner::HandleSecureCoapClientConnect(bool aConnected, void *aContext)
{
static_cast<Joiner *>(aContext)->SendJoinerFinalize();
static_cast<Joiner *>(aContext)->HandleSecureCoapClientConnect(aConnected);
}
void Joiner::HandleSecureCoapClientConnect(bool aConnected)
{
switch (mState)
{
case kStateConnect:
if (aConnected)
{
mState = kStateConnected;
SendJoinerFinalize();
mTimer.Start(kTimeout);
}
else
{
Complete(kThreadError_Security);
}
break;
default:
break;
}
}
void Joiner::SendJoinerFinalize(void)
@@ -247,13 +298,17 @@ void Joiner::HandleJoinerFinalizeResponse(Coap::Header *aHeader, Message *aMessa
otLogFuncEntry();
VerifyOrExit(aResult == kThreadError_None &&
VerifyOrExit(mState == kStateConnected &&
aResult == kThreadError_None &&
aHeader->GetType() == kCoapTypeAcknowledgment &&
aHeader->GetCode() == kCoapResponseChanged, ;);
SuccessOrExit(Tlv::GetTlv(*aMessage, Tlv::kState, sizeof(state), state));
VerifyOrExit(state.IsValid(), ;);
mState = kStateEntrust;
mTimer.Start(kTimeout);
otLogInfoMeshCoP("received joiner finalize response %d", static_cast<uint8_t>(state.GetState()));
otLogCertMeshCoP("[THCI] direction=recv | type=JOIN_FIN.rsp");
@@ -282,7 +337,8 @@ void Joiner::HandleJoinerEntrust(Coap::Header &aHeader, Message &aMessage, const
otLogFuncEntry();
VerifyOrExit(aHeader.GetType() == kCoapTypeConfirmable &&
VerifyOrExit(mState == kStateEntrust &&
aHeader.GetType() == kCoapTypeConfirmable &&
aHeader.GetCode() == kCoapRequestPost, error = kThreadError_Drop);
otLogInfoMeshCoP("Received joiner entrust");
@@ -340,6 +396,8 @@ void Joiner::SendJoinerEntrustResponse(const Coap::Header &aRequestHeader,
memset(&responseInfo.mSockAddr, 0, sizeof(responseInfo.mSockAddr));
SuccessOrExit(error = mCoapServer.SendMessage(*message, responseInfo));
mState = kStateJoined;
otLogInfoArp("Sent Joiner Entrust response");
exit:
@@ -359,15 +417,38 @@ void Joiner::HandleTimer(void *aContext)
void Joiner::HandleTimer(void)
{
Mac::ExtAddress extAddress;
ThreadError error = kThreadError_Error;
for (size_t i = 0; i < sizeof(extAddress); i++)
switch (mState)
{
extAddress.m8[i] = static_cast<uint8_t>(otPlatRandomGet());
case kStateIdle:
case kStateDiscover:
case kStateConnect:
assert(false);
break;
case kStateConnected:
case kStateEntrust:
error = kThreadError_ResponseTimeout;
break;
case kStateJoined:
Mac::ExtAddress extAddress;
for (size_t i = 0; i < sizeof(extAddress); i++)
{
extAddress.m8[i] = static_cast<uint8_t>(otPlatRandomGet());
}
mNetif.GetMac().SetExtAddress(extAddress);
mNetif.GetMle().UpdateLinkLocalAddress();
error = kThreadError_None;
break;
}
mNetif.GetMac().SetExtAddress(extAddress);
mNetif.GetMle().UpdateLinkLocalAddress();
Complete(error);
}
} // namespace MeshCoP
+22 -2
View File
@@ -35,6 +35,7 @@
#define JOINER_HPP_
#include <openthread-types.h>
#include <commissioning/joiner.h>
#include <coap/coap_header.hpp>
#include <coap/coap_server.hpp>
@@ -66,11 +67,13 @@ public:
*
* @param[in] aPSKd A pointer to the PSKd.
* @param[in] aProvisioningUrl A pointer to the Provisioning URL (may be NULL).
* @param[in] aCallback A pointer to a function that is called when the join operation completes.
* @param[in] aContext A pointer to application-specific context.
*
* @retval kThreadError_None Successfully started the Joiner service.
*
*/
ThreadError Start(const char *aPSKd, const char *aProvisioningUrl);
ThreadError Start(const char *aPSKd, const char *aProvisioningUrl, otJoinerCallback aCallback, void *aContext);
/**
* This method stops the Joiner service.
@@ -84,6 +87,7 @@ private:
enum
{
kConfigExtAddressDelay = 100, ///< milliseconds
kTimeout = 4000, ///< milliseconds
};
static void HandleDiscoverResult(otActiveScanResult *aResult, void *aContext);
@@ -93,8 +97,10 @@ private:
void HandleTimer(void);
void Close(void);
void Complete(ThreadError aError);
static void HandleSecureCoapClientConnect(void *aContext);
static void HandleSecureCoapClientConnect(bool aConnected, void *aContext);
void HandleSecureCoapClientConnect(bool aConnected);
void SendJoinerFinalize(void);
static void HandleJoinerFinalizeResponse(void *aContext, otCoapHeader *aHeader, otMessage aMessage,
@@ -107,6 +113,20 @@ private:
void HandleJoinerEntrust(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void SendJoinerEntrustResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestInfo);
enum State
{
kStateIdle = 0,
kStateDiscover = 1,
kStateConnect = 2,
kStateConnected = 3,
kStateEntrust = 4,
kStateJoined = 5,
};
State mState;
otJoinerCallback mCallback;
void *mContext;
uint8_t mJoinerRouterChannel;
uint16_t mJoinerRouterPanId;
uint16_t mJoinerUdpPort;
+3 -2
View File
@@ -1690,9 +1690,10 @@ uint16_t otCommissionerGetSessionId(otInstance *aInstance)
#endif // OPENTHREAD_ENABLE_COMMISSIONER
#if OPENTHREAD_ENABLE_JOINER
ThreadError otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl)
ThreadError otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl,
otJoinerCallback aCallback, void *aContext)
{
return aInstance->mThreadNetif.GetJoiner().Start(aPSKd, aProvisioningUrl);
return aInstance->mThreadNetif.GetJoiner().Start(aPSKd, aProvisioningUrl, aCallback, aContext);
}
ThreadError otJoinerStop(otInstance *aInstance)