From d4063fe9b8cf3762904bbf5b29fda740a42e5867 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Thu, 2 May 2019 16:00:53 -0700 Subject: [PATCH] [cli] clean up coaps example implementation (#3795) --- src/cli/cli_coap_secure.cpp | 659 +++++++++++++------------- src/cli/cli_coap_secure.hpp | 38 +- tests/scripts/thread-cert/node_cli.py | 8 +- 3 files changed, 345 insertions(+), 360 deletions(-) diff --git a/src/cli/cli_coap_secure.cpp b/src/cli/cli_coap_secure.cpp index 61904c859..ce4c33f7b 100644 --- a/src/cli/cli_coap_secure.cpp +++ b/src/cli/cli_coap_secure.cpp @@ -46,6 +46,15 @@ namespace ot { namespace Cli { +const struct CoapSecure::Command CoapSecure::sCommands[] = { + {"help", &CoapSecure::ProcessHelp}, {"connect", &CoapSecure::ProcessConnect}, + {"delete", &CoapSecure::ProcessRequest}, {"disconnect", &CoapSecure::ProcessDisconnect}, + {"get", &CoapSecure::ProcessRequest}, {"post", &CoapSecure::ProcessRequest}, + {"psk", &CoapSecure::ProcessPsk}, {"put", &CoapSecure::ProcessRequest}, + {"resource", &CoapSecure::ProcessResource}, {"start", &CoapSecure::ProcessStart}, + {"stop", &CoapSecure::ProcessStop}, {"x509", &CoapSecure::ProcessX509}, +}; + CoapSecure::CoapSecure(Interpreter &aInterpreter) : mInterpreter(aInterpreter) , mShutdownFlag(false) @@ -58,39 +67,6 @@ CoapSecure::CoapSecure(Interpreter &aInterpreter) memset(&mPskId, 0, sizeof(mPskId)); } -void CoapSecure::PrintHeaderInfos(otMessage *aMessage) const -{ - otCoapCode mCoapCode; - otCoapType mCoapType; - - mCoapCode = otCoapMessageGetCode(aMessage); - mCoapType = otCoapMessageGetType(aMessage); - - mInterpreter.mServer->OutputFormat("\r\n CoapSecure RX Header Information:" - "\r\n Type %d => ", - static_cast(mCoapType)); - - switch (mCoapType) - { - case OT_COAP_TYPE_ACKNOWLEDGMENT: - mInterpreter.mServer->OutputFormat("Ack"); - break; - case OT_COAP_TYPE_CONFIRMABLE: - mInterpreter.mServer->OutputFormat("Confirmable"); - break; - case OT_COAP_TYPE_NON_CONFIRMABLE: - mInterpreter.mServer->OutputFormat("NonConfirmable"); - break; - case OT_COAP_TYPE_RESET: - mInterpreter.mServer->OutputFormat("Reset"); - break; - default: - break; - } - mInterpreter.mServer->OutputFormat("\r\n Code %d => %s\r\n", static_cast(mCoapCode), - static_cast(otCoapMessageCodeToString(aMessage))); -} - void CoapSecure::PrintPayload(otMessage *aMessage) const { uint8_t buf[kMaxBufferSize]; @@ -100,341 +76,108 @@ void CoapSecure::PrintPayload(otMessage *aMessage) const if (length > 0) { - mInterpreter.mServer->OutputFormat(" With payload [UTF8]:\r\n", aMessage); + mInterpreter.mServer->OutputFormat(" with payload: "); while (length > 0) { bytesToPrint = (length < sizeof(buf)) ? length : sizeof(buf); otMessageRead(aMessage, otMessageGetOffset(aMessage) + bytesPrinted, buf, bytesToPrint); - for (int i = 0; i < bytesToPrint; i++) - { - mInterpreter.mServer->OutputFormat("%c", buf[i]); - } - mInterpreter.mServer->OutputFormat("\r\n"); + mInterpreter.OutputBytes(buf, static_cast(bytesToPrint)); length -= bytesToPrint; bytesPrinted += bytesToPrint; } } - else - { - mInterpreter.mServer->OutputFormat(" No payload."); - } - mInterpreter.mServer->OutputFormat("\r\n> "); + mInterpreter.mServer->OutputFormat("\r\n"); } -otError CoapSecure::Process(int argc, char *argv[]) +otError CoapSecure::ProcessHelp(int argc, char *argv[]) { - otError error = OT_ERROR_NONE; - bool mVerifyPeerCert = true; - long value; + OT_UNUSED_VARIABLE(argc); + OT_UNUSED_VARIABLE(argv); - VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS); - - if (strcmp(argv[0], "start") == 0) + for (size_t i = 0; i < OT_ARRAY_LENGTH(sCommands); i++) { - if (argc > 1) - { - if (strcmp(argv[1], "false") == 0) - { - mVerifyPeerCert = false; - } - else if (strcmp(argv[1], "true") != 0) - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - otCoapSecureSetSslAuthMode(mInterpreter.mInstance, mVerifyPeerCert); - SuccessOrExit(error = otCoapSecureStart(mInterpreter.mInstance, OT_DEFAULT_COAP_SECURE_PORT)); - otCoapSecureSetClientConnectedCallback(mInterpreter.mInstance, &CoapSecure::HandleClientConnect, this); -#if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER - otCoapSecureSetDefaultHandler(mInterpreter.mInstance, &CoapSecure::DefaultHandler, this); -#endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER -#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - if (mUseCertificate) - { - mInterpreter.mServer->OutputFormat("Verify Peer Certificate: %s. Coap Secure service started: ", - mVerifyPeerCert ? "true" : "false"); - } -#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + mInterpreter.mServer->OutputFormat("%s\r\n", sCommands[i].mName); } - else if (strcmp(argv[0], "set") == 0) + + return OT_ERROR_NONE; +} + +otError CoapSecure::ProcessResource(int argc, char *argv[]) +{ + otError error = OT_ERROR_NONE; + + if (argc > 1) { - if (argc > 1) - { - if (strcmp(argv[1], "psk") == 0) - { - if (argc > 3) - { - size_t length; + VerifyOrExit(strlen(argv[1]) < kMaxUriLength, error = OT_ERROR_INVALID_ARGS); - length = strlen(argv[2]); - VerifyOrExit(length <= sizeof(mPsk), error = OT_ERROR_INVALID_ARGS); - mPskLength = static_cast(length); - memcpy(mPsk, argv[2], mPskLength); - - length = strlen(argv[3]); - VerifyOrExit(length <= sizeof(mPskId), error = OT_ERROR_INVALID_ARGS); - mPskIdLength = static_cast(length); - memcpy(mPskId, argv[3], mPskIdLength); - - SuccessOrExit( - error = otCoapSecureSetPsk(mInterpreter.mInstance, mPsk, mPskLength, mPskId, mPskIdLength)); - mUseCertificate = false; - mInterpreter.mServer->OutputFormat("Coap Secure set PSK: "); - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - else if (strcmp(argv[1], "x509") == 0) - { -#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - SuccessOrExit(error = otCoapSecureSetCertificate( - mInterpreter.mInstance, (const uint8_t *)OT_CLI_COAPS_X509_CERT, - sizeof(OT_CLI_COAPS_X509_CERT), (const uint8_t *)OT_CLI_COAPS_PRIV_KEY, - sizeof(OT_CLI_COAPS_PRIV_KEY))); - - SuccessOrExit(error = otCoapSecureSetCaCertificateChain( - mInterpreter.mInstance, (const uint8_t *)OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE, - sizeof(OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE))); - mUseCertificate = true; - - mInterpreter.mServer->OutputFormat("Coap Secure set own .X509 certificate: "); -#else - ExitNow(error = OT_ERROR_DISABLED_FEATURE); -#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - else if (strcmp(argv[0], "connect") == 0) - { - // Destination IPv6 address - if (argc > 1) - { - otSockAddr sockaddr; - - memset(&sockaddr, 0, sizeof(sockaddr)); - SuccessOrExit(error = otIp6AddressFromString(argv[1], &sockaddr.mAddress)); - sockaddr.mPort = OT_DEFAULT_COAP_SECURE_PORT; - sockaddr.mScopeId = OT_NETIF_INTERFACE_ID_THREAD; - - // check for port specification - if (argc > 2) - { - error = Interpreter::ParseLong(argv[2], value); - SuccessOrExit(error); - sockaddr.mPort = static_cast(value); - } - - SuccessOrExit( - error = otCoapSecureConnect(mInterpreter.mInstance, &sockaddr, &CoapSecure::HandleClientConnect, this)); - mInterpreter.mServer->OutputFormat("Coap Secure connect: "); - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - else if (strcmp(argv[0], "resource") == 0) - { mResource.mUriPath = mUriPath; mResource.mContext = this; - mResource.mHandler = &CoapSecure::HandleServerResponse; + mResource.mHandler = &CoapSecure::HandleRequest; - if (argc > 1) - { - strlcpy(mUriPath, argv[1], kMaxUriLength); - SuccessOrExit(error = otCoapSecureAddResource(mInterpreter.mInstance, &mResource)); - } - - mInterpreter.mServer->OutputFormat("Resource name is '%s': ", mResource.mUriPath); - } - else if (strcmp(argv[0], "disconnect") == 0) - { - otCoapSecureDisconnect(mInterpreter.mInstance); - } - else if (strcmp(argv[0], "stop") == 0) - { - if (otCoapSecureIsConnectionActive(mInterpreter.mInstance)) - { - otCoapSecureDisconnect(mInterpreter.mInstance); - mShutdownFlag = true; - } - else - { - Stop(); - } - } - else if (strcmp(argv[0], "help") == 0) - { - mInterpreter.mServer->OutputFormat("CLI CoAPS help:\r\n\r\n"); - mInterpreter.mServer->OutputFormat(">'coaps start (false)' " - ": start coap secure service, false disable peer cert verification\r\n"); - mInterpreter.mServer->OutputFormat(">'coaps set psk ' " - ": set Preshared Key and Client Identity (Ciphersuite PSK_AES128)\r\n"); - mInterpreter.mServer->OutputFormat(">'coaps set x509' " - ": set X509 Cert und Private Key (Ciphersuite ECDHE_ECDSA_AES128)\r\n"); - mInterpreter.mServer->OutputFormat(">'coaps connect (port)' " - ": start dtls session with a server\r\n"); - mInterpreter.mServer->OutputFormat(">'coaps get' 'coaps put' 'coaps post' 'coaps delete' " - ": interact with coap resource from server, ipv6 is not need as client\r\n"); - mInterpreter.mServer->OutputFormat( - " >> args:(ipv6_addr_srv) and, if you have payload: \r\n"); - mInterpreter.mServer->OutputFormat(">'coaps resource ' " - ": add a coap server resource with 'helloWorld' as content.\r\n"); - mInterpreter.mServer->OutputFormat(">'coaps disconnect' " - ": stop dtls session with a server\r\n"); - mInterpreter.mServer->OutputFormat(">'coaps stop' " - ": stop coap secure service\r\n"); - mInterpreter.mServer->OutputFormat("\r\n legend: <>: must, (): opt " - "\r\n"); - mInterpreter.mServer->OutputFormat("\r\n"); + strlcpy(mUriPath, argv[1], kMaxUriLength); + SuccessOrExit(error = otCoapSecureAddResource(mInterpreter.mInstance, &mResource)); } else { - error = ProcessRequest(argc, argv); + mInterpreter.mServer->OutputFormat("%s\r\n", mResource.mUriPath); } +exit: + return OT_ERROR_NONE; +} + +otError CoapSecure::ProcessStart(int argc, char *argv[]) +{ + otError error; + bool verifyPeerCert = true; + + if (argc > 1) + { + if (strcmp(argv[1], "false") == 0) + { + verifyPeerCert = false; + } + else if (strcmp(argv[1], "true") != 0) + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + + otCoapSecureSetSslAuthMode(mInterpreter.mInstance, verifyPeerCert); + otCoapSecureSetClientConnectedCallback(mInterpreter.mInstance, &CoapSecure::HandleConnected, this); + +#if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER + otCoapSecureSetDefaultHandler(mInterpreter.mInstance, &CoapSecure::DefaultHandler, this); +#endif + + SuccessOrExit(error = otCoapSecureStart(mInterpreter.mInstance, OT_DEFAULT_COAP_SECURE_PORT)); + exit: return error; } -void CoapSecure::Stop(void) +otError CoapSecure::ProcessStop(int argc, char *argv[]) { + OT_UNUSED_VARIABLE(argc); + OT_UNUSED_VARIABLE(argv); + otCoapRemoveResource(mInterpreter.mInstance, &mResource); - otCoapSecureStop(mInterpreter.mInstance); - mInterpreter.mServer->OutputFormat("Coap Secure service stopped"); -} -void OTCALL CoapSecure::HandleClientConnect(bool aConnected, void *aContext) -{ - static_cast(aContext)->HandleClientConnect(aConnected); -} - -void CoapSecure::HandleClientConnect(bool aConnected) -{ - OT_UNUSED_VARIABLE(aConnected); - - if (aConnected) + if (otCoapSecureIsConnectionActive(mInterpreter.mInstance)) { - mInterpreter.mServer->OutputFormat("CoAP Secure connected!\r\n> "); + otCoapSecureDisconnect(mInterpreter.mInstance); + mShutdownFlag = true; } else { - if (!mShutdownFlag) - { - mInterpreter.mServer->OutputFormat("CoAP Secure not connected or disconnected.\r\n> "); - } - else - { - mInterpreter.mServer->OutputFormat("CoAP Secure disconnected before stop.\r\n> "); - Stop(); - mInterpreter.mServer->OutputFormat(" Done\r\n> "); - mShutdownFlag = false; - } - } -} - -void OTCALL CoapSecure::HandleServerResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleServerResponse(aMessage, aMessageInfo); -} - -void CoapSecure::HandleServerResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - otError error = OT_ERROR_NONE; - otMessage *responseMessage = NULL; - otCoapCode responseCode = OT_COAP_CODE_EMPTY; - char responseContent[] = "helloWorld"; - - mInterpreter.mServer->OutputFormat( - "Received coap secure request from [%x:%x:%x:%x:%x:%x:%x:%x]: ", - HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[0]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[1]), - HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[2]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[3]), - HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[4]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[5]), - HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[6]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[7])); - - switch (otCoapMessageGetCode(aMessage)) - { - case OT_COAP_CODE_GET: - mInterpreter.mServer->OutputFormat("GET"); - break; - - case OT_COAP_CODE_DELETE: - mInterpreter.mServer->OutputFormat("DELETE"); - break; - - case OT_COAP_CODE_PUT: - mInterpreter.mServer->OutputFormat("PUT"); - break; - - case OT_COAP_CODE_POST: - mInterpreter.mServer->OutputFormat("POST"); - break; - - default: - mInterpreter.mServer->OutputFormat("Undefined\r\n"); - return; + Stop(); } - PrintPayload(aMessage); - - if ((otCoapMessageGetType(aMessage) == OT_COAP_TYPE_CONFIRMABLE) || - (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)) - { - if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET) - { - responseCode = OT_COAP_CODE_CONTENT; - } - else - { - responseCode = OT_COAP_CODE_VALID; - } - - responseMessage = otCoapNewMessage(mInterpreter.mInstance, NULL); - VerifyOrExit(responseMessage != NULL, error = OT_ERROR_NO_BUFS); - - otCoapMessageInit(responseMessage, OT_COAP_TYPE_ACKNOWLEDGMENT, responseCode); - otCoapMessageSetMessageId(responseMessage, otCoapMessageGetMessageId(aMessage)); - otCoapMessageSetToken(responseMessage, otCoapMessageGetToken(aMessage), otCoapMessageGetTokenLength(aMessage)); - - if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET) - { - otCoapMessageSetPayloadMarker(responseMessage); - } - - if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET) - { - SuccessOrExit(error = otMessageAppend(responseMessage, &responseContent, sizeof(responseContent))); - } - - SuccessOrExit(error = otCoapSecureSendResponse(mInterpreter.mInstance, responseMessage, aMessageInfo)); - } - -exit: - - if (error != OT_ERROR_NONE && responseMessage != NULL) - { - mInterpreter.mServer->OutputFormat("Cannot send coap secure response message: Error %d: %s\r\n", error, - otThreadErrorToString(error)); - otMessageFree(responseMessage); - } - else if (responseCode >= OT_COAP_CODE_RESPONSE_MIN) - { - mInterpreter.mServer->OutputFormat("coap secure response sent successfully!\r\n"); - } + return OT_ERROR_NONE; } otError CoapSecure::ProcessRequest(int argc, char *argv[]) @@ -541,15 +284,13 @@ otError CoapSecure::ProcessRequest(int argc, char *argv[]) if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (coapCode == OT_COAP_CODE_GET)) { - error = otCoapSecureSendRequest(mInterpreter.mInstance, message, &CoapSecure::HandleClientResponse, this); + error = otCoapSecureSendRequest(mInterpreter.mInstance, message, &CoapSecure::HandleResponse, this); } else { error = otCoapSecureSendRequest(mInterpreter.mInstance, message, NULL, NULL); } - mInterpreter.mServer->OutputFormat("Sending coap secure request: "); - exit: if ((error != OT_ERROR_NONE) && (message != NULL)) @@ -560,33 +301,268 @@ exit: return error; } -void OTCALL CoapSecure::HandleClientResponse(void * aContext, - otMessage * aMessage, - const otMessageInfo *aMessageInfo, - otError aError) +otError CoapSecure::ProcessConnect(int argc, char *argv[]) { - static_cast(aContext)->HandleClientResponse(aMessage, aMessageInfo, aError); + otError error; + otSockAddr sockaddr; + + VerifyOrExit(argc > 1, error = OT_ERROR_INVALID_ARGS); + + // Destination IPv6 address + memset(&sockaddr, 0, sizeof(sockaddr)); + SuccessOrExit(error = otIp6AddressFromString(argv[1], &sockaddr.mAddress)); + sockaddr.mPort = OT_DEFAULT_COAP_SECURE_PORT; + sockaddr.mScopeId = OT_NETIF_INTERFACE_ID_THREAD; + + // check for port specification + if (argc > 2) + { + long value; + + error = Interpreter::ParseLong(argv[2], value); + SuccessOrExit(error); + sockaddr.mPort = static_cast(value); + } + + SuccessOrExit(error = otCoapSecureConnect(mInterpreter.mInstance, &sockaddr, &CoapSecure::HandleConnected, this)); + +exit: + return error; } -void CoapSecure::HandleClientResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError) +otError CoapSecure::ProcessDisconnect(int argc, char *argv[]) +{ + OT_UNUSED_VARIABLE(argc); + OT_UNUSED_VARIABLE(argv); + + otCoapSecureDisconnect(mInterpreter.mInstance); + + return OT_ERROR_NONE; +} + +otError CoapSecure::ProcessPsk(int argc, char *argv[]) +{ + otError error; + size_t length; + + VerifyOrExit(argc > 2, error = OT_ERROR_INVALID_ARGS); + + length = strlen(argv[1]); + VerifyOrExit(length <= sizeof(mPsk), error = OT_ERROR_INVALID_ARGS); + mPskLength = static_cast(length); + memcpy(mPsk, argv[1], mPskLength); + + length = strlen(argv[2]); + VerifyOrExit(length <= sizeof(mPskId), error = OT_ERROR_INVALID_ARGS); + mPskIdLength = static_cast(length); + memcpy(mPskId, argv[2], mPskIdLength); + + SuccessOrExit(error = otCoapSecureSetPsk(mInterpreter.mInstance, mPsk, mPskLength, mPskId, mPskIdLength)); + mUseCertificate = false; + +exit: + return error; +} + +otError CoapSecure::ProcessX509(int argc, char *argv[]) +{ + OT_UNUSED_VARIABLE(argc); + OT_UNUSED_VARIABLE(argv); + +#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + otError error; + + SuccessOrExit(error = otCoapSecureSetCertificate( + mInterpreter.mInstance, (const uint8_t *)OT_CLI_COAPS_X509_CERT, sizeof(OT_CLI_COAPS_X509_CERT), + (const uint8_t *)OT_CLI_COAPS_PRIV_KEY, sizeof(OT_CLI_COAPS_PRIV_KEY))); + + SuccessOrExit(error = otCoapSecureSetCaCertificateChain(mInterpreter.mInstance, + (const uint8_t *)OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE, + sizeof(OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE))); + mUseCertificate = true; + +exit: + return error; +#else + return OT_ERROR_DISABLED_FEATURE +#endif +} + +otError CoapSecure::Process(int argc, char *argv[]) +{ + otError error = OT_ERROR_PARSE; + + if (argc < 1) + { + ProcessHelp(0, NULL); + error = OT_ERROR_INVALID_ARGS; + } + else + { + for (size_t i = 0; i < OT_ARRAY_LENGTH(sCommands); i++) + { + if (strcmp(argv[0], sCommands[i].mName) == 0) + { + error = (this->*sCommands[i].mCommand)(argc, argv); + break; + } + } + } + + return error; +} + +void CoapSecure::Stop(void) +{ + otCoapRemoveResource(mInterpreter.mInstance, &mResource); + otCoapSecureStop(mInterpreter.mInstance); +} + +void CoapSecure::HandleConnected(bool aConnected, void *aContext) +{ + static_cast(aContext)->HandleConnected(aConnected); +} + +void CoapSecure::HandleConnected(bool aConnected) +{ + if (aConnected) + { + mInterpreter.mServer->OutputFormat("coaps connected\r\n"); + } + else + { + mInterpreter.mServer->OutputFormat("coaps disconnected\r\n"); + + if (mShutdownFlag) + { + Stop(); + mShutdownFlag = false; + } + } +} + +void CoapSecure::HandleRequest(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) +{ + static_cast(aContext)->HandleRequest(aMessage, aMessageInfo); +} + +void CoapSecure::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo) +{ + otError error = OT_ERROR_NONE; + otMessage *responseMessage = NULL; + otCoapCode responseCode = OT_COAP_CODE_EMPTY; + char responseContent[] = "helloWorld"; + + mInterpreter.mServer->OutputFormat( + "coaps request from [%x:%x:%x:%x:%x:%x:%x:%x] ", HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[0]), + HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[1]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[2]), + HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[3]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[4]), + HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[5]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[6]), + HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[7])); + + switch (otCoapMessageGetCode(aMessage)) + { + case OT_COAP_CODE_GET: + mInterpreter.mServer->OutputFormat("GET"); + break; + + case OT_COAP_CODE_DELETE: + mInterpreter.mServer->OutputFormat("DELETE"); + break; + + case OT_COAP_CODE_PUT: + mInterpreter.mServer->OutputFormat("PUT"); + break; + + case OT_COAP_CODE_POST: + mInterpreter.mServer->OutputFormat("POST"); + break; + + default: + mInterpreter.mServer->OutputFormat("Undefined\r\n"); + return; + } + + PrintPayload(aMessage); + + if ((otCoapMessageGetType(aMessage) == OT_COAP_TYPE_CONFIRMABLE) || + (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)) + { + if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET) + { + responseCode = OT_COAP_CODE_CONTENT; + } + else + { + responseCode = OT_COAP_CODE_VALID; + } + + responseMessage = otCoapNewMessage(mInterpreter.mInstance, NULL); + VerifyOrExit(responseMessage != NULL, error = OT_ERROR_NO_BUFS); + + otCoapMessageInit(responseMessage, OT_COAP_TYPE_ACKNOWLEDGMENT, responseCode); + otCoapMessageSetMessageId(responseMessage, otCoapMessageGetMessageId(aMessage)); + otCoapMessageSetToken(responseMessage, otCoapMessageGetToken(aMessage), otCoapMessageGetTokenLength(aMessage)); + + if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET) + { + otCoapMessageSetPayloadMarker(responseMessage); + } + + if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET) + { + SuccessOrExit(error = otMessageAppend(responseMessage, &responseContent, sizeof(responseContent))); + } + + SuccessOrExit(error = otCoapSecureSendResponse(mInterpreter.mInstance, responseMessage, aMessageInfo)); + } + +exit: + + if (error != OT_ERROR_NONE) + { + if (responseMessage != NULL) + { + mInterpreter.mServer->OutputFormat("coaps send response error %d: %s\r\n", error, + otThreadErrorToString(error)); + otMessageFree(responseMessage); + } + } + else if (responseCode >= OT_COAP_CODE_RESPONSE_MIN) + { + mInterpreter.mServer->OutputFormat("coaps response sent\r\n"); + } +} + +void CoapSecure::HandleResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError) +{ + static_cast(aContext)->HandleResponse(aMessage, aMessageInfo, aError); +} + +void CoapSecure::HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError) { OT_UNUSED_VARIABLE(aMessageInfo); if (aError != OT_ERROR_NONE) { - mInterpreter.mServer->OutputFormat("Error receiving coap secure response message: Error %d: %s\r\n", aError, + mInterpreter.mServer->OutputFormat("coaps receive response error %d: %s\r\n", aError, otThreadErrorToString(aError)); } else { - mInterpreter.mServer->OutputFormat("Received coap secure response"); - PrintHeaderInfos(aMessage); + mInterpreter.mServer->OutputFormat( + "coaps response from [%x:%x:%x:%x:%x:%x:%x:%x]", HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[0]), + HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[1]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[2]), + HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[3]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[4]), + HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[5]), HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[6]), + HostSwap16(aMessageInfo->mPeerAddr.mFields.m16[7])); + PrintPayload(aMessage); } } #if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER -void OTCALL CoapSecure::DefaultHandler(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) +void CoapSecure::DefaultHandler(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) { static_cast(aContext)->DefaultHandler(aMessage, aMessageInfo); } @@ -610,8 +586,7 @@ void CoapSecure::DefaultHandler(otMessage *aMessage, const otMessageInfo *aMessa } exit: - - mInterpreter.mServer->OutputFormat("Default handler called.\r\n> "); + return; } #endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER diff --git a/src/cli/cli_coap_secure.hpp b/src/cli/cli_coap_secure.hpp index 2ffdb7e50..3c9bd08b8 100644 --- a/src/cli/cli_coap_secure.hpp +++ b/src/cli/cli_coap_secure.hpp @@ -79,36 +79,46 @@ private: kPskIdMaxLength = 32 }; - void PrintHeaderInfos(otMessage *aMessage) const; + struct Command + { + const char *mName; + otError (CoapSecure::*mCommand)(int argc, char *argv[]); + }; void PrintPayload(otMessage *aMessage) const; + otError ProcessHelp(int argc, char *argv[]); + otError ProcessConnect(int argc, char *argv[]); + otError ProcessDisconnect(int argc, char *argv[]); + otError ProcessPsk(int argc, char *argv[]); otError ProcessRequest(int argc, char *argv[]); + otError ProcessResource(int argc, char *argv[]); + otError ProcessStart(int argc, char *argv[]); + otError ProcessStop(int argc, char *argv[]); + otError ProcessX509(int argc, char *argv[]); void Stop(void); - static void OTCALL HandleServerResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleServerResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo); + static void HandleRequest(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); + void HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo); - static void OTCALL HandleClientResponse(void * aContext, - otMessage * aMessage, - const otMessageInfo *aMessageInfo, - otError aError); - void HandleClientResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError); + static void HandleResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError); + void HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError); #if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER - static void OTCALL DefaultHandler(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void DefaultHandler(otMessage *aMessage, const otMessageInfo *aMessageInfo); + static void DefaultHandler(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); + void DefaultHandler(otMessage *aMessage, const otMessageInfo *aMessageInfo); #endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER - static void OTCALL HandleClientConnect(bool aConnected, void *aContext); - void HandleClientConnect(bool aConnected); + static void HandleConnected(bool aConnected, void *aContext); + void HandleConnected(bool aConnected); + + static const Command sCommands[]; + Interpreter & mInterpreter; otCoapResource mResource; char mUriPath[kMaxUriLength]; - Interpreter &mInterpreter; - bool mShutdownFlag; bool mUseCertificate; uint8_t mPsk[kPskMaxLength]; diff --git a/tests/scripts/thread-cert/node_cli.py b/tests/scripts/thread-cert/node_cli.py index 9aabea497..5ebc45947 100644 --- a/tests/scripts/thread-cert/node_cli.py +++ b/tests/scripts/thread-cert/node_cli.py @@ -854,7 +854,7 @@ class otCli: self._expect('Done') def coaps_start_psk(self, psk, pskIdentity): - cmd = 'coaps set psk ' + psk + ' ' + pskIdentity + cmd = 'coaps psk ' + psk + ' ' + pskIdentity self.send_command(cmd) self._expect('Done') @@ -863,7 +863,7 @@ class otCli: self._expect('Done') def coaps_start_x509(self): - cmd = 'coaps set x509' + cmd = 'coaps x509' self.send_command(cmd) self._expect('Done') @@ -898,7 +898,7 @@ class otCli: else: timeout = 5 - self._expect('CoAP Secure connected!', timeout=timeout) + self._expect('coaps connected', timeout=timeout) def coaps_disconnect(self): cmd = 'coaps disconnect' @@ -916,7 +916,7 @@ class otCli: else: timeout = 5 - self._expect('Received coap secure response', timeout=timeout) + self._expect('coaps response', timeout=timeout) def commissioner_mgmtset(self, tlvs_binary): cmd = 'commissioner mgmtset binary ' + tlvs_binary