diff --git a/components/protocomm/include/common/protocomm.h b/components/protocomm/include/common/protocomm.h index f5f67da64..239d71390 100644 --- a/components/protocomm/include/common/protocomm.h +++ b/components/protocomm/include/common/protocomm.h @@ -17,6 +17,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Function prototype for protocomm endpoint handler */ @@ -42,7 +46,7 @@ typedef struct protocomm protocomm_t; * @brief Create a new protocomm instance * * This API will return a new dynamically allocated protocomm instance - * with all elements of the protocomm_t structure initialised to NULL. + * with all elements of the protocomm_t structure initialized to NULL. * * @return * - protocomm_t* : On success @@ -71,7 +75,8 @@ void protocomm_delete(protocomm_t *pc); * - An endpoint must be bound to a valid protocomm instance, * created using `protocomm_new()`. * - This function internally calls the registered `add_endpoint()` - * function which is a member of the protocomm_t instance structure. + * function of the selected transport which is a member of the + * protocomm_t instance structure. * * @param[in] pc Pointer to the protocomm instance * @param[in] ep_name Endpoint identifier(name) string @@ -81,7 +86,7 @@ void protocomm_delete(protocomm_t *pc); * Pass NULL if not needed. * * @return - * - ESP_OK : Added new endpoint succesfully + * - ESP_OK : Success * - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists * - ESP_ERR_NO_MEM : Error allocating endpoint resource * - ESP_ERR_INVALID_ARG : Null instance/name/handler arguments @@ -103,7 +108,7 @@ esp_err_t protocomm_add_endpoint(protocomm_t *pc, const char *ep_name, * @param[in] ep_name Endpoint identifier(name) string * * @return - * - ESP_OK : Added new endpoint succesfully + * - ESP_OK : Success * - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist * - ESP_ERR_INVALID_ARG : Null instance/name arguments */ @@ -111,12 +116,12 @@ esp_err_t protocomm_remove_endpoint(protocomm_t *pc, const char *ep_name); /** * @brief Calls the registered handler of an endpoint session - * for processing incoming data and giving the output + * for processing incoming data and generating the response * * @note * - An endpoint must be bound to a valid protocomm instance, * created using `protocomm_new()`. - * - Resulting output buffer must be deallocated by the user. + * - Resulting output buffer must be deallocated by the caller. * * @param[in] pc Pointer to the protocomm instance * @param[in] ep_name Endpoint identifier(name) string @@ -130,7 +135,7 @@ esp_err_t protocomm_remove_endpoint(protocomm_t *pc, const char *ep_name); * @param[out] outlen Buffer length of the allocated output buffer * * @return - * - ESP_OK : Request handled succesfully + * - ESP_OK : Request handled successfully * - ESP_FAIL : Internal error in execution of registered handler * - ESP_ERR_NO_MEM : Error allocating internal resource * - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist @@ -159,7 +164,7 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se * @param[in] pop Pointer to proof of possession for authenticating a client * * @return - * - ESP_OK : Added new security endpoint succesfully + * - ESP_OK : Success * - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists * - ESP_ERR_INVALID_STATE : Security endpoint already set * - ESP_ERR_NO_MEM : Error allocating endpoint resource @@ -179,7 +184,7 @@ esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name, * @param[in] ep_name Endpoint identifier(name) string * * @return - * - ESP_OK : Added new endpoint succesfully + * - ESP_OK : Success * - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist * - ESP_ERR_INVALID_ARG : Null instance/name arguments */ @@ -189,7 +194,7 @@ esp_err_t protocomm_unset_security(protocomm_t *pc, const char *ep_name); * @brief Set endpoint for version verification * * This API can be used for setting an application specific protocol - * version which can be verfied by clients through the endpoint. + * version which can be verified by clients through the endpoint. * * @note * - An endpoint must be bound to a valid protocomm instance, @@ -200,7 +205,7 @@ esp_err_t protocomm_unset_security(protocomm_t *pc, const char *ep_name); * @param[in] version Version identifier(name) string * * @return - * - ESP_OK : Added new security endpoint succesfully + * - ESP_OK : Success * - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists * - ESP_ERR_INVALID_STATE : Version endpoint already set * - ESP_ERR_NO_MEM : Error allocating endpoint resource @@ -219,8 +224,12 @@ esp_err_t protocomm_set_version(protocomm_t *pc, const char *ep_name, * @param[in] ep_name Endpoint identifier(name) string * * @return - * - ESP_OK : Added new endpoint succesfully + * - ESP_OK : Success * - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist * - ESP_ERR_INVALID_ARG : Null instance/name arguments */ esp_err_t protocomm_unset_version(protocomm_t *pc, const char *ep_name); + +#ifdef __cplusplus +} +#endif diff --git a/components/protocomm/include/security/protocomm_security.h b/components/protocomm/include/security/protocomm_security.h index 7eeecc16f..28f43a657 100644 --- a/components/protocomm/include/security/protocomm_security.h +++ b/components/protocomm/include/security/protocomm_security.h @@ -16,6 +16,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Proof Of Possession for authenticating a secure session */ @@ -42,12 +46,12 @@ typedef struct protocomm_security_pop { */ typedef struct protocomm_security { /** - * Unique version number of security implmentation + * Unique version number of security implementation */ int ver; /** - * Function for initialising/allocating security + * Function for initializing/allocating security * infrastructure */ esp_err_t (*init)(); @@ -91,3 +95,7 @@ typedef struct protocomm_security { const uint8_t *inbuf, ssize_t inlen, uint8_t *outbuf, ssize_t *outlen); } protocomm_security_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/protocomm/include/security/protocomm_security0.h b/components/protocomm/include/security/protocomm_security0.h index 7d0462d8e..9ae8744d4 100644 --- a/components/protocomm/include/security/protocomm_security0.h +++ b/components/protocomm/include/security/protocomm_security0.h @@ -16,6 +16,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Protocomm security version 0 implementation * @@ -23,3 +27,7 @@ * security is required for the protocomm instance */ extern const protocomm_security_t protocomm_security0; + +#ifdef __cplusplus +} +#endif diff --git a/components/protocomm/include/security/protocomm_security1.h b/components/protocomm/include/security/protocomm_security1.h index 098d61e6a..12a05c322 100644 --- a/components/protocomm/include/security/protocomm_security1.h +++ b/components/protocomm/include/security/protocomm_security1.h @@ -16,10 +16,18 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Protocomm security version 1 implementation * - * This is a full fledged security implmentation using + * This is a full fledged security implementation using * Curve25519 key exchange and AES-256-CTR encryption */ extern const protocomm_security_t protocomm_security1; + +#ifdef __cplusplus +} +#endif diff --git a/components/protocomm/include/transports/protocomm_ble.h b/components/protocomm/include/transports/protocomm_ble.h index b86059e57..562ea608c 100644 --- a/components/protocomm/include/transports/protocomm_ble.h +++ b/components/protocomm/include/transports/protocomm_ble.h @@ -16,6 +16,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * BLE device name cannot be larger than this value */ @@ -30,7 +34,7 @@ typedef struct name_uuid { /** * Name of the handler, which is passed to protocomm layer */ - char *name; + const char *name; /** * UUID to be assigned to the BLE characteristic which is @@ -63,10 +67,10 @@ typedef struct { * the initialization for characteristics/service for BLE. * * @param[in] pc Protocomm instance pointer obtained from protocomm_new() - * @param[in] config Pointer to config structure for initialising BLE + * @param[in] config Pointer to config structure for initializing BLE * * @return - * - ESP_OK : if successful + * - ESP_OK : Success * - ESP_FAIL : Simple BLE start error * - ESP_ERR_NO_MEM : Error allocating memory for internal resources * - ESP_ERR_INVALID_STATE : Error in ble config @@ -85,8 +89,12 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con * @param[in] pc Same protocomm instance that was passed to protocomm_ble_start() * * @return - * - ESP_OK : For success or appropriate error code + * - ESP_OK : Success * - ESP_FAIL : Simple BLE stop error * - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance */ esp_err_t protocomm_ble_stop(protocomm_t *pc); + +#ifdef __cplusplus +} +#endif diff --git a/components/protocomm/include/transports/protocomm_console.h b/components/protocomm/include/transports/protocomm_console.h index b7004d02b..767bcd7ca 100644 --- a/components/protocomm/include/transports/protocomm_console.h +++ b/components/protocomm/include/transports/protocomm_console.h @@ -16,6 +16,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + #define PROTOCOMM_CONSOLE_DEFAULT_CONFIG() { \ .stack_size = 4096, \ .task_priority = tskIDLE_PRIORITY + 3, \ @@ -25,7 +29,7 @@ * @brief Config parameters for protocomm console */ typedef struct { - size_t stack_size; /*!< Stack size of console taks */ + size_t stack_size; /*!< Stack size of console task */ unsigned task_priority; /*!< Priority of console task */ } protocomm_console_config_t; @@ -39,7 +43,7 @@ typedef struct { * @param[in] config Config param structure for protocomm console * * @return - * - ESP_OK : Server started succefully + * - ESP_OK : Success * - ESP_ERR_INVALID_ARG : Null arguments * - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance * - ESP_ERR_INVALID_STATE : Transport layer already bound to this protocomm instance @@ -53,7 +57,11 @@ esp_err_t protocomm_console_start(protocomm_t *pc, const protocomm_console_confi * @param[in] pc Same protocomm instance that was passed to protocomm_console_start() * * @return - * - ESP_OK : Server stopped succefully + * - ESP_OK : Success * - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer */ esp_err_t protocomm_console_stop(protocomm_t *pc); + +#ifdef __cplusplus +} +#endif diff --git a/components/protocomm/include/transports/protocomm_httpd.h b/components/protocomm/include/transports/protocomm_httpd.h index 701fa9683..2baf75455 100644 --- a/components/protocomm/include/transports/protocomm_httpd.h +++ b/components/protocomm/include/transports/protocomm_httpd.h @@ -22,11 +22,16 @@ .task_priority = tskIDLE_PRIORITY + 5, \ } +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Config parameters for protocomm HTTP server */ typedef struct { - uint16_t port; /*!< Port on which the http server will listen */ + + uint16_t port; /*!< Port on which the HTTP server will listen */ /** * Stack size of server task, adjusted depending @@ -34,6 +39,31 @@ typedef struct { */ size_t stack_size; unsigned task_priority; /*!< Priority of server task */ +} protocomm_http_server_config_t; /*!< HTTP Server Configuration, if HTTP Server has not been started already */ + +/** Protocomm HTTPD Configuration Data + */ +typedef union { + /** HTTP Server Handle, if ext_handle_provided is set to true + */ + void *handle; + + /** HTTP Server Configuration, if a server is not already active + */ + protocomm_http_server_config_t config; +} protocomm_httpd_config_data_t; + +/** + * @brief Config parameters for protocomm HTTP server + */ +typedef struct { + /** Flag to indicate of an external HTTP Server Handle has been provided. + * In such as case, protocomm will use the same HTTP Server and not start + * a new one internally. + */ + bool ext_handle_provided; + /** Protocomm HTTPD Configuration Data */ + protocomm_httpd_config_data_t data; } protocomm_httpd_config_t; /** @@ -46,10 +76,10 @@ typedef struct { * one instance can be bound to an HTTP transport layer. * * @param[in] pc Protocomm instance pointer obtained from protocomm_new() - * @param[in] config Pointer to config structure for initialising HTTP server + * @param[in] config Pointer to config structure for initializing HTTP server * * @return - * - ESP_OK : Server started succefully + * - ESP_OK : Success * - ESP_ERR_INVALID_ARG : Null arguments * - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance * - ESP_ERR_INVALID_STATE : Transport layer already bound to this protocomm instance @@ -67,7 +97,11 @@ esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t * @param[in] pc Same protocomm instance that was passed to protocomm_httpd_start() * * @return - * - ESP_OK : Server stopped succefully + * - ESP_OK : Success * - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer */ esp_err_t protocomm_httpd_stop(protocomm_t *pc); + +#ifdef __cplusplus +} +#endif diff --git a/components/protocomm/src/common/protocomm.c b/components/protocomm/src/common/protocomm.c index 94ebc8e81..687efdbab 100644 --- a/components/protocomm/src/common/protocomm.c +++ b/components/protocomm/src/common/protocomm.c @@ -52,6 +52,19 @@ void protocomm_delete(protocomm_t *pc) free(it); } + /* Free memory allocated to version string */ + if (pc->ver) { + free((void *)pc->ver); + } + + /* Free memory allocated to security */ + if (pc->sec && pc->sec->cleanup) { + pc->sec->cleanup(); + } + if (pc->pop) { + free(pc->pop); + } + free(pc); } @@ -140,11 +153,14 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen) { - if ((pc == NULL) || (ep_name == NULL)) { + if (!pc || !ep_name || !outbuf || !outlen) { ESP_LOGE(TAG, "Invalid params %p %p", pc, ep_name); return ESP_ERR_INVALID_ARG; } + *outbuf = NULL; + *outlen = 0; + protocomm_ep_t *ep = search_endpoint(pc, ep_name); if (!ep) { ESP_LOGE(TAG, "No registered endpoint for %s", ep_name); @@ -166,19 +182,23 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se } ssize_t dec_inbuf_len = inlen; - pc->sec->decrypt(session_id, inbuf, inlen, dec_inbuf, &dec_inbuf_len); + ret = pc->sec->decrypt(session_id, inbuf, inlen, dec_inbuf, &dec_inbuf_len); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Decryption of response failed for endpoint %s", ep_name); + free(dec_inbuf); + return ret; + } /* Invoke the request handler */ - uint8_t *plaintext_resp; - ssize_t plaintext_resp_len; + uint8_t *plaintext_resp = NULL; + ssize_t plaintext_resp_len = 0; ret = ep->req_handler(session_id, dec_inbuf, dec_inbuf_len, &plaintext_resp, &plaintext_resp_len, ep->priv_data); if (ret != ESP_OK) { ESP_LOGE(TAG, "Request handler for %s failed", ep_name); - *outbuf = NULL; - *outlen = 0; + free(plaintext_resp); free(dec_inbuf); return ret; } @@ -189,12 +209,20 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se uint8_t *enc_resp = (uint8_t *) malloc(plaintext_resp_len); if (!enc_resp) { ESP_LOGE(TAG, "Failed to allocate decrypt buf len %d", inlen); + free(plaintext_resp); return ESP_ERR_NO_MEM; } ssize_t enc_resp_len = plaintext_resp_len; - pc->sec->encrypt(session_id, plaintext_resp, plaintext_resp_len, - enc_resp, &enc_resp_len); + ret = pc->sec->encrypt(session_id, plaintext_resp, plaintext_resp_len, + enc_resp, &enc_resp_len); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Encryption of response failed for endpoint %s", ep_name); + free(enc_resp); + free(plaintext_resp); + return ret; + } /* We no more need plaintext response */ free(plaintext_resp); @@ -257,7 +285,7 @@ esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name, if (sec->init) { ret = sec->init(); if (ret != ESP_OK) { - ESP_LOGE(TAG, "Error initialising security"); + ESP_LOGE(TAG, "Error initializing security"); protocomm_remove_endpoint(pc, ep_name); return ret; } @@ -305,40 +333,22 @@ static int protocomm_version_handler(uint32_t session_id, uint8_t **outbuf, ssize_t *outlen, void *priv_data) { - const char *resp_match = "SUCCESS"; - const char *resp_fail = "FAIL"; - bool match = false; - char *version = strndup((const char *)inbuf, inlen); protocomm_t *pc = (protocomm_t *) priv_data; - *outbuf = NULL; - *outlen = 0; - - if ((pc->ver != NULL) && (version != NULL)) { - ESP_LOGV(TAG, "Protocol version of device : %s", pc->ver); - ESP_LOGV(TAG, "Protocol version of client : %s", version); - if (strcmp(pc->ver, version) == 0) { - match = true; - } - } else if ((pc->ver == NULL) && (version == NULL)) { - match = true; + if (!pc->ver) { + *outlen = 0; + *outbuf = NULL; + return ESP_OK; } - free(version); - - if (!match) { - ESP_LOGE(TAG, "Protocol version mismatch"); - } - - const char *result_msg = match ? resp_match : resp_fail; /* Output is a non null terminated string with length specified */ - *outlen = strlen(result_msg); - *outbuf = malloc(strlen(result_msg)); + *outlen = strlen(pc->ver); + *outbuf = malloc(*outlen); if (outbuf == NULL) { - ESP_LOGE(TAG, "Failed to allocate memory for version check response"); + ESP_LOGE(TAG, "Failed to allocate memory for version response"); return ESP_ERR_NO_MEM; } - memcpy(*outbuf, result_msg, *outlen); + memcpy(*outbuf, pc->ver, *outlen); return ESP_OK; } diff --git a/components/protocomm/src/common/protocomm_priv.h b/components/protocomm/src/common/protocomm_priv.h index e956c3fd0..895d11015 100644 --- a/components/protocomm/src/common/protocomm_priv.h +++ b/components/protocomm/src/common/protocomm_priv.h @@ -62,7 +62,7 @@ struct protocomm { int (*remove_endpoint)(const char *ep_name); /* Pointer to security layer instance to be used internally for - * establising secure sessions */ + * establishing secure sessions */ const protocomm_security_t *sec; /* Pointer to proof of possession object */ diff --git a/components/protocomm/src/security/security0.c b/components/protocomm/src/security/security0.c index bca4d18c3..a127136a3 100644 --- a/components/protocomm/src/security/security0.c +++ b/components/protocomm/src/security/security0.c @@ -36,6 +36,8 @@ static esp_err_t sec0_session_setup(uint32_t session_id, S0SessionResp *s0resp = (S0SessionResp *) malloc(sizeof(S0SessionResp)); if (!out || !s0resp) { ESP_LOGE(TAG, "Error allocating response"); + free(out); + free(s0resp); return ESP_ERR_NO_MEM; } sec0_payload__init(out); @@ -79,6 +81,7 @@ static esp_err_t sec0_req_handler(const protocomm_security_pop_t *pop, uint32_t } if (req->sec_ver != protocomm_security0.ver) { ESP_LOGE(TAG, "Security version mismatch. Closing connection"); + session_data__free_unpacked(req, NULL); return ESP_ERR_INVALID_ARG; } @@ -86,12 +89,12 @@ static esp_err_t sec0_req_handler(const protocomm_security_pop_t *pop, uint32_t ret = sec0_session_setup(session_id, req, &resp, pop); if (ret != ESP_OK) { ESP_LOGE(TAG, "Session setup error %d", ret); + session_data__free_unpacked(req, NULL); return ESP_FAIL; } - session_data__free_unpacked(req, NULL); - resp.sec_ver = req->sec_ver; + session_data__free_unpacked(req, NULL); *outlen = session_data__get_packed_size(&resp); *outbuf = (uint8_t *) malloc(*outlen); diff --git a/components/protocomm/src/security/security1.c b/components/protocomm/src/security/security1.c index 76b9a25f5..36d99f0a2 100644 --- a/components/protocomm/src/security/security1.c +++ b/components/protocomm/src/security/security1.c @@ -38,8 +38,9 @@ static const char* TAG = "security1"; #define PUBLIC_KEY_LEN 32 #define SZ_RANDOM 16 -#define SESSION_STATE_1 1 /* Session in state 1 */ -#define SESSION_STATE_SETUP 2 /* Session setup successful */ +#define SESSION_STATE_CMD0 0 /* Session is not setup */ +#define SESSION_STATE_CMD1 1 /* Session is not setup */ +#define SESSION_STATE_DONE 2 /* Session setup successful */ typedef struct session { /* Session data */ @@ -82,22 +83,12 @@ static esp_err_t handle_session_command1(uint32_t session_id, uint8_t check_buf[PUBLIC_KEY_LEN]; int mbed_err; - if (!cur_session) { - ESP_LOGE(TAG, "Data on session endpoint without session establishment"); + if (cur_session->state != SESSION_STATE_CMD1) { + ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD1, cur_session->state); return ESP_ERR_INVALID_STATE; } - if (session_id != cur_session->id) { - ESP_LOGE(TAG, "Invalid session"); - return ESP_ERR_INVALID_STATE; - } - - if (!in) { - ESP_LOGE(TAG, "Empty session data"); - return ESP_ERR_INVALID_ARG; - } - - /* Initialise crypto context */ + /* Initialize crypto context */ mbedtls_aes_init(&cur_session->ctx_aes); memset(cur_session->stb, 0, sizeof(cur_session->stb)); cur_session->nc_off = 0; @@ -109,6 +100,7 @@ static esp_err_t handle_session_command1(uint32_t session_id, sizeof(cur_session->sym_key)*8); if (mbed_err != 0) { ESP_LOGE(TAG, "Failure at mbedtls_aes_setkey_enc with error code : -0x%x", -mbed_err); + mbedtls_aes_free(&cur_session->ctx_aes); return ESP_FAIL; } @@ -118,6 +110,7 @@ static esp_err_t handle_session_command1(uint32_t session_id, in->sc1->client_verify_data.data, check_buf); if (mbed_err != 0) { ESP_LOGE(TAG, "Failure at mbedtls_aes_crypt_ctr with error code : -0x%x", -mbed_err); + mbedtls_aes_free(&cur_session->ctx_aes); return ESP_FAIL; } @@ -127,19 +120,30 @@ static esp_err_t handle_session_command1(uint32_t session_id, if (mbedtls_ssl_safer_memcmp(check_buf, cur_session->device_pubkey, sizeof(cur_session->device_pubkey)) != 0) { ESP_LOGE(TAG, "Key mismatch. Close connection"); + mbedtls_aes_free(&cur_session->ctx_aes); return ESP_FAIL; } Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload)); - sec1_payload__init(out); SessionResp1 *out_resp = (SessionResp1 *) malloc(sizeof(SessionResp1)); - session_resp1__init(out_resp); + if (!out || !out_resp) { + ESP_LOGE(TAG, "Error allocating memory for response1"); + free(out); + free(out_resp); + mbedtls_aes_free(&cur_session->ctx_aes); + return ESP_ERR_NO_MEM; + } + sec1_payload__init(out); + session_resp1__init(out_resp); out_resp->status = STATUS__Success; uint8_t *outbuf = (uint8_t *) malloc(PUBLIC_KEY_LEN); if (!outbuf) { ESP_LOGE(TAG, "Error allocating ciphertext buffer"); + free(out); + free(out_resp); + mbedtls_aes_free(&cur_session->ctx_aes); return ESP_ERR_NO_MEM; } @@ -149,6 +153,10 @@ static esp_err_t handle_session_command1(uint32_t session_id, cur_session->client_pubkey, outbuf); if (mbed_err != 0) { ESP_LOGE(TAG, "Failure at mbedtls_aes_crypt_ctr with error code : -0x%x", -mbed_err); + free(outbuf); + free(out); + free(out_resp); + mbedtls_aes_free(&cur_session->ctx_aes); return ESP_FAIL; } @@ -163,8 +171,8 @@ static esp_err_t handle_session_command1(uint32_t session_id, resp->proto_case = SESSION_DATA__PROTO_SEC1; resp->sec1 = out; - ESP_LOGD(TAG, "Session successful"); - + cur_session->state = SESSION_STATE_DONE; + ESP_LOGD(TAG, "Secure session established successfully"); return ESP_OK; } @@ -172,32 +180,21 @@ static esp_err_t handle_session_command0(uint32_t session_id, SessionData *req, SessionData *resp, const protocomm_security_pop_t *pop) { + ESP_LOGD(TAG, "Request to handle setup0_command"); Sec1Payload *in = (Sec1Payload *) req->sec1; esp_err_t ret; int mbed_err; - if (!cur_session) { - ESP_LOGE(TAG, "Data on session endpoint without session establishment"); + if (cur_session->state != SESSION_STATE_CMD0) { + ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD0, cur_session->state); return ESP_ERR_INVALID_STATE; } - if (session_id != cur_session->id) { - ESP_LOGE(TAG, "Invalid session"); - return ESP_ERR_INVALID_STATE; - } - - if (!in) { - ESP_LOGE(TAG, "Empty session data"); - return ESP_ERR_INVALID_ARG; - } - if (in->sc0->client_pubkey.len != PUBLIC_KEY_LEN) { ESP_LOGE(TAG, "Invalid public key length"); return ESP_ERR_INVALID_ARG; } - cur_session->state = SESSION_STATE_1; - mbedtls_ecdh_context *ctx_server = malloc(sizeof(mbedtls_ecdh_context)); mbedtls_entropy_context *entropy = malloc(sizeof(mbedtls_entropy_context)); mbedtls_ctr_drbg_context *ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_context)); @@ -315,8 +312,10 @@ static esp_err_t handle_session_command0(uint32_t session_id, Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload)); SessionResp0 *out_resp = (SessionResp0 *) malloc(sizeof(SessionResp0)); if (!out || !out_resp) { - ESP_LOGE(TAG, "Error allocating memory for response"); - ret = ESP_FAIL; + ESP_LOGE(TAG, "Error allocating memory for response0"); + ret = ESP_ERR_NO_MEM; + free(out); + free(out_resp); goto exit_cmd0; } @@ -338,6 +337,8 @@ static esp_err_t handle_session_command0(uint32_t session_id, resp->proto_case = SESSION_DATA__PROTO_SEC1; resp->sec1 = out; + cur_session->state = SESSION_STATE_CMD1; + ESP_LOGD(TAG, "Session setup phase1 done"); ret = ESP_OK; @@ -361,6 +362,21 @@ static esp_err_t sec1_session_setup(uint32_t session_id, Sec1Payload *in = (Sec1Payload *) req->sec1; esp_err_t ret; + if (!cur_session) { + ESP_LOGE(TAG, "Invalid session context data"); + return ESP_ERR_INVALID_ARG; + } + + if (session_id != cur_session->id) { + ESP_LOGE(TAG, "Invalid session ID : %d (expected %d)", session_id, cur_session->id); + return ESP_ERR_INVALID_STATE; + } + + if (!in) { + ESP_LOGE(TAG, "Empty session data"); + return ESP_ERR_INVALID_ARG; + } + switch (in->msg) { case SEC1_MSG_TYPE__Session_Command0: ret = handle_session_command0(session_id, req, resp, pop); @@ -411,30 +427,30 @@ static void sec1_session_setup_cleanup(uint32_t session_id, SessionData *resp) return; } -static esp_err_t sec1_init() +static esp_err_t sec1_close_session(uint32_t session_id) { - return ESP_OK; -} - -static esp_err_t sec1_cleanup() -{ - if (cur_session) { - ESP_LOGD(TAG, "Closing current session with id %u", cur_session->id); - mbedtls_aes_free(&cur_session->ctx_aes); - bzero(cur_session, sizeof(session_t)); - free(cur_session); - cur_session = NULL; + if (!cur_session || cur_session->id != session_id) { + ESP_LOGE(TAG, "Attempt to close invalid session"); + return ESP_ERR_INVALID_ARG; } + + if (cur_session->state == SESSION_STATE_DONE) { + /* Free AES context data */ + mbedtls_aes_free(&cur_session->ctx_aes); + } + + bzero(cur_session, sizeof(session_t)); + free(cur_session); + cur_session = NULL; return ESP_OK; } static esp_err_t sec1_new_session(uint32_t session_id) { - if (cur_session && cur_session->id != session_id) { + if (cur_session) { + /* Only one session is allowed at a time */ ESP_LOGE(TAG, "Closing old session with id %u", cur_session->id); - sec1_cleanup(); - } else if (cur_session && cur_session->id == session_id) { - return ESP_OK; + sec1_close_session(cur_session->id); } cur_session = (session_t *) calloc(1, sizeof(session_t)); @@ -447,16 +463,17 @@ static esp_err_t sec1_new_session(uint32_t session_id) return ESP_OK; } -static esp_err_t sec1_close_session(uint32_t session_id) +static esp_err_t sec1_init() { - if (!cur_session || cur_session->id != session_id) { - ESP_LOGE(TAG, "Attempt to close invalid session"); - return ESP_ERR_INVALID_ARG; - } + return ESP_OK; +} - bzero(cur_session, sizeof(session_t)); - free(cur_session); - cur_session = NULL; +static esp_err_t sec1_cleanup() +{ + if (cur_session) { + ESP_LOGD(TAG, "Closing current session with id %u", cur_session->id); + sec1_close_session(cur_session->id); + } return ESP_OK; } @@ -469,8 +486,15 @@ static esp_err_t sec1_decrypt(uint32_t session_id, } if (!cur_session || cur_session->id != session_id) { + ESP_LOGE(TAG, "Session with ID %d not found", session_id); return ESP_ERR_INVALID_STATE; } + + if (cur_session->state != SESSION_STATE_DONE) { + ESP_LOGE(TAG, "Secure session not established"); + return ESP_ERR_INVALID_STATE; + } + *outlen = inlen; int ret = mbedtls_aes_crypt_ctr(&cur_session->ctx_aes, inlen, &cur_session->nc_off, cur_session->rand, cur_session->stb, inbuf, outbuf); @@ -497,6 +521,7 @@ static esp_err_t sec1_req_handler(const protocomm_security_pop_t *pop, uint32_t } if (req->sec_ver != protocomm_security1.ver) { ESP_LOGE(TAG, "Security version mismatch. Closing connection"); + session_data__free_unpacked(req, NULL); return ESP_ERR_INVALID_ARG; } @@ -504,12 +529,12 @@ static esp_err_t sec1_req_handler(const protocomm_security_pop_t *pop, uint32_t ret = sec1_session_setup(session_id, req, &resp, pop); if (ret != ESP_OK) { ESP_LOGE(TAG, "Session setup error %d", ret); + session_data__free_unpacked(req, NULL); return ESP_FAIL; } - session_data__free_unpacked(req, NULL); - resp.sec_ver = req->sec_ver; + session_data__free_unpacked(req, NULL); *outlen = session_data__get_packed_size(&resp); *outbuf = (uint8_t *) malloc(*outlen); diff --git a/components/protocomm/src/simple_ble/simple_ble.c b/components/protocomm/src/simple_ble/simple_ble.c index e52be0053..f29f1a348 100644 --- a/components/protocomm/src/simple_ble/simple_ble.c +++ b/components/protocomm/src/simple_ble/simple_ble.c @@ -103,7 +103,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_ g_ble_cfg_p->exec_write_fn(event, gatts_if, param); break; case ESP_GATTS_MTU_EVT: - ESP_LOGV(TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu); + ESP_LOGD(TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu); if (g_ble_cfg_p->set_mtu_fn) { g_ble_cfg_p->set_mtu_fn(event, gatts_if, param); } diff --git a/components/protocomm/src/simple_ble/simple_ble.h b/components/protocomm/src/simple_ble/simple_ble.h index 892cd4d55..4402429f6 100644 --- a/components/protocomm/src/simple_ble/simple_ble.h +++ b/components/protocomm/src/simple_ble/simple_ble.h @@ -55,7 +55,7 @@ typedef struct { } simple_ble_cfg_t; -/** Initialise a simple ble connection +/** Initialize a simple ble connection * * This function allocates memory and returns a pointer to the * configuration structure. diff --git a/components/protocomm/src/transports/protocomm_ble.c b/components/protocomm/src/transports/protocomm_ble.c index a4b1927d0..b374f055e 100644 --- a/components/protocomm/src/transports/protocomm_ble.c +++ b/components/protocomm/src/transports/protocomm_ble.c @@ -276,7 +276,7 @@ static void transport_simple_ble_exec_write(esp_gatts_cb_event_t event, esp_gatt static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { esp_err_t ret; - ESP_LOGV(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id); + ESP_LOGD(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id); if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->close_transport_session) { ret = protoble_internal->pc_ble->sec->close_transport_session(param->disconnect.conn_id); @@ -290,7 +290,7 @@ static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { esp_err_t ret; - ESP_LOGV(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id); + ESP_LOGD(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id); if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->new_transport_session) { ret = protoble_internal->pc_ble->sec->new_transport_session(param->connect.conn_id); @@ -372,7 +372,7 @@ static void protocomm_ble_cleanup(void) if (protoble_internal->g_nu_lookup) { for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) { if (protoble_internal->g_nu_lookup[i].name) { - free(protoble_internal->g_nu_lookup[i].name); + free((void *)protoble_internal->g_nu_lookup[i].name); } } free(protoble_internal->g_nu_lookup); @@ -488,7 +488,7 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con } prepare_write_env.prepare_buf = NULL; - ESP_LOGV(TAG, "Waiting for client to connect ......"); + ESP_LOGD(TAG, "Waiting for client to connect ......"); return ESP_OK; } diff --git a/components/protocomm/src/transports/protocomm_console.c b/components/protocomm/src/transports/protocomm_console.c index c7cf8c921..e1e10a772 100644 --- a/components/protocomm/src/transports/protocomm_console.c +++ b/components/protocomm/src/transports/protocomm_console.c @@ -76,7 +76,7 @@ static void protocomm_console_task(void *arg) QueueHandle_t uart_queue; uart_event_t event; - ESP_LOGV(TAG, "Initialising UART on port %d", uart_num); + ESP_LOGD(TAG, "Initializing UART on port %d", uart_num); uart_driver_install(uart_num, 256, 0, 8, &uart_queue, 0); /* Initialize the console */ esp_console_config_t console_config = { @@ -121,10 +121,6 @@ static void protocomm_console_task(void *arg) } } - if (pc_console->sec && pc_console->sec->cleanup) { - pc_console->sec->cleanup(); - } - pc_console = NULL; esp_console_deinit(); diff --git a/components/protocomm/src/transports/protocomm_httpd.c b/components/protocomm/src/transports/protocomm_httpd.c index a7c9b5599..b4653b9a5 100644 --- a/components/protocomm/src/transports/protocomm_httpd.c +++ b/components/protocomm/src/transports/protocomm_httpd.c @@ -26,6 +26,7 @@ static const char *TAG = "protocomm_httpd"; static protocomm_t *pc_httpd; /* The global protocomm instance for HTTPD */ +static bool pc_ext_httpd_handle_provided = false; static uint32_t session_id = PROTOCOMM_NO_SESSION_ID; #define MAX_REQ_BODY_LEN 4096 @@ -41,9 +42,9 @@ static esp_err_t common_post_handler(httpd_req_t *req) int cur_session_id = httpd_req_to_sockfd(req); if (cur_session_id != session_id) { - /* Initialise new security session */ + /* Initialize new security session */ if (session_id != PROTOCOMM_NO_SESSION_ID) { - ESP_LOGV(TAG, "Closing session with ID: %d", session_id); + ESP_LOGD(TAG, "Closing session with ID: %d", session_id); /* Presently HTTP server doesn't support callback on socket closure so * previous session can only be closed when new session is requested */ if (pc_httpd->sec && pc_httpd->sec->close_transport_session) { @@ -65,7 +66,7 @@ static esp_err_t common_post_handler(httpd_req_t *req) } } session_id = cur_session_id; - ESP_LOGV(TAG, "New session with ID: %d", cur_session_id); + ESP_LOGD(TAG, "New session with ID: %d", cur_session_id); } if (req->content_len <= 0) { @@ -124,7 +125,7 @@ out: return ret; } -esp_err_t protocomm_httpd_add_endpoint(const char *ep_name, +static esp_err_t protocomm_httpd_add_endpoint(const char *ep_name, protocomm_req_handler_t req_handler, void *priv_data) { @@ -132,7 +133,7 @@ esp_err_t protocomm_httpd_add_endpoint(const char *ep_name, return ESP_ERR_INVALID_STATE; } - ESP_LOGV(TAG, "Adding endpoint : %s", ep_name); + ESP_LOGD(TAG, "Adding endpoint : %s", ep_name); /* Construct URI name by prepending '/' to ep_name */ char* ep_uri = calloc(1, strlen(ep_name) + 2); @@ -169,7 +170,7 @@ static esp_err_t protocomm_httpd_remove_endpoint(const char *ep_name) return ESP_ERR_INVALID_STATE; } - ESP_LOGV(TAG, "Removing endpoint : %s", ep_name); + ESP_LOGD(TAG, "Removing endpoint : %s", ep_name); /* Construct URI name by prepending '/' to ep_name */ char* ep_uri = calloc(1, strlen(ep_name) + 2); @@ -207,28 +208,36 @@ esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t return ESP_ERR_NOT_SUPPORTED; } - /* Private data will point to the HTTP server handle */ - pc->priv = calloc(1, sizeof(httpd_handle_t)); - if (!pc->priv) { - ESP_LOGE(TAG, "Malloc failed for HTTP server handle"); - return ESP_ERR_NO_MEM; + if (config->ext_handle_provided) { + if (config->data.handle) { + pc->priv = config->data.handle; + pc_ext_httpd_handle_provided = true; + } else { + return ESP_ERR_INVALID_ARG; + } + } else { + /* Private data will point to the HTTP server handle */ + pc->priv = calloc(1, sizeof(httpd_handle_t)); + if (!pc->priv) { + ESP_LOGE(TAG, "Malloc failed for HTTP server handle"); + return ESP_ERR_NO_MEM; + } + + /* Configure the HTTP server */ + httpd_config_t server_config = HTTPD_DEFAULT_CONFIG(); + server_config.server_port = config->data.config.port; + server_config.stack_size = config->data.config.stack_size; + server_config.task_priority = config->data.config.task_priority; + server_config.lru_purge_enable = true; + server_config.max_open_sockets = 1; + + esp_err_t err; + if ((err = httpd_start((httpd_handle_t *)pc->priv, &server_config)) != ESP_OK) { + ESP_LOGE(TAG, "Failed to start http server: %s", esp_err_to_name(err)); + free(pc->priv); + return err; + } } - - /* Configure the HTTP server */ - httpd_config_t server_config = HTTPD_DEFAULT_CONFIG(); - server_config.server_port = config->port; - server_config.stack_size = config->stack_size; - server_config.task_priority = config->task_priority; - server_config.lru_purge_enable = true; - server_config.max_open_sockets = 1; - - esp_err_t err; - if ((err = httpd_start((httpd_handle_t *)pc->priv, &server_config)) != ESP_OK) { - ESP_LOGE(TAG, "Failed to start http server: %s", esp_err_to_name(err)); - free(pc->priv); - return err; - } - pc->add_endpoint = protocomm_httpd_add_endpoint; pc->remove_endpoint = protocomm_httpd_remove_endpoint; pc_httpd = pc; @@ -238,9 +247,13 @@ esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t esp_err_t protocomm_httpd_stop(protocomm_t *pc) { if ((pc != NULL) && (pc == pc_httpd)) { - httpd_handle_t *server_handle = (httpd_handle_t *) pc_httpd->priv; - httpd_stop(*server_handle); - free(server_handle); + if (!pc_ext_httpd_handle_provided) { + httpd_handle_t *server_handle = (httpd_handle_t *) pc_httpd->priv; + httpd_stop(*server_handle); + free(server_handle); + } else { + pc_ext_httpd_handle_provided = false; + } pc_httpd->priv = NULL; pc_httpd = NULL; return ESP_OK; diff --git a/components/protocomm/test/test_protocomm.c b/components/protocomm/test/test_protocomm.c index cc8500649..d9a3a71a0 100644 --- a/components/protocomm/test/test_protocomm.c +++ b/components/protocomm/test/test_protocomm.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,7 @@ #include "session.pb-c.h" -#ifdef DO_HEAP_TRACING +#ifdef CONFIG_HEAP_TRACING #include #define NUM_RECORDS 100 static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM @@ -492,6 +493,30 @@ abort_test_sec_endpoint: return ESP_FAIL; } +#define TEST_VER_STR "" + +static esp_err_t test_ver_endpoint(session_t *session) +{ + ssize_t ver_data_len = 0; + uint8_t *ver_data = NULL; + + esp_err_t ret = protocomm_req_handle(test_pc, "test-ver", session->id, + NULL, 0, &ver_data, &ver_data_len); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "test-ver handler failed"); + return ESP_FAIL; + } + + if (ver_data_len != strlen(TEST_VER_STR) || memcmp(TEST_VER_STR, ver_data, ver_data_len)) { + ESP_LOGE(TAG, "incorrect response data from test-ver"); + free(ver_data); + return ESP_FAIL; + } + free(ver_data); + return ESP_OK; +} + static esp_err_t test_req_endpoint(session_t *session) { uint32_t session_id = session->id; @@ -514,7 +539,7 @@ static esp_err_t test_req_endpoint(session_t *session) enc_test_data, sizeof(enc_test_data), &enc_verify_data, &verify_data_len); - if (ret != ESP_OK) { + if (ret != ESP_OK || !verify_data_len) { ESP_LOGE(TAG, "test-ep handler failed"); return ESP_FAIL; } @@ -600,6 +625,11 @@ static esp_err_t start_test_service(uint8_t sec_ver, const protocomm_security_po test_sec = &protocomm_security1; } + if (protocomm_set_version(test_pc, "test-ver", TEST_VER_STR) != ESP_OK) { + ESP_LOGE(TAG, "Failed to set version"); + return ESP_FAIL; + } + if (protocomm_add_endpoint(test_pc, "test-ep", test_req_handler, (void *) &test_priv_data) != ESP_OK) { @@ -611,8 +641,6 @@ static esp_err_t start_test_service(uint8_t sec_ver, const protocomm_security_po static void stop_test_service(void) { - protocomm_remove_endpoint(test_pc, "test-ep"); - protocomm_unset_security(test_pc, "test-sec"); test_sec = NULL; protocomm_delete(test_pc); test_pc = NULL; @@ -913,8 +941,8 @@ static esp_err_t test_security1_weak_session (void) } // Sending request data to echo endpoint encrypted with zero - // public keys on both client and server side should pass - if (test_req_endpoint(session) != ESP_OK) { + // public keys on both client and server side should fail + if (test_req_endpoint(session) == ESP_OK) { ESP_LOGE(TAG, "Error testing request endpoint"); stop_test_service(); free(session); @@ -938,6 +966,13 @@ static esp_err_t test_protocomm (session_t *session) return ESP_FAIL; } + // Check version endpoint + if (test_ver_endpoint(session) != ESP_OK) { + ESP_LOGE(TAG, "Error testing version endpoint"); + stop_test_service(); + return ESP_FAIL; + } + // Intialise protocomm session with zero public keys if (test_new_session(session) != ESP_OK) { ESP_LOGE(TAG, "Error creating new session"); @@ -1024,33 +1059,43 @@ static esp_err_t test_security0 (void) TEST_CASE("leak test", "[PROTOCOMM]") { -#ifdef DO_HEAP_TRACING +#ifdef CONFIG_HEAP_TRACING heap_trace_init_standalone(trace_record, NUM_RECORDS); -#endif - - unsigned pre_start_mem = esp_get_free_heap_size(); - -#ifdef DO_HEAP_TRACING heap_trace_start(HEAP_TRACE_LEAKS); #endif + /* Run basic tests for the first time to allow for internal long + * time allocations to happen (not related to protocomm) */ test_security0(); test_security1(); + usleep(1000); -#ifdef DO_HEAP_TRACING +#ifdef CONFIG_HEAP_TRACING heap_trace_stop(); heap_trace_dump(); #endif + /* Run all tests passively. Any leaks due + * to protocomm should show up now */ + unsigned pre_start_mem = esp_get_free_heap_size(); + + test_security0(); + test_security1(); + test_security1_no_encryption(); + test_security1_session_overflow(); + test_security1_wrong_pop(); + test_security1_insecure_client(); + test_security1_weak_session(); + + usleep(1000); + unsigned post_stop_mem = esp_get_free_heap_size(); if (pre_start_mem != post_stop_mem) { - ESP_LOGE(TAG, "Mismatch in free heap size"); + ESP_LOGE(TAG, "Mismatch in free heap size : %d bytes", post_stop_mem - pre_start_mem); } -#ifdef DO_HEAP_TRACING - TEST_ASSERT(pre_start_mem != post_stop_mem); -#endif + TEST_ASSERT(pre_start_mem == post_stop_mem); } TEST_CASE("security 0 basic test", "[PROTOCOMM]") diff --git a/components/wifi_provisioning/include/wifi_provisioning/wifi_config.h b/components/wifi_provisioning/include/wifi_provisioning/wifi_config.h index 2794ae47d..4058540ad 100644 --- a/components/wifi_provisioning/include/wifi_provisioning/wifi_config.h +++ b/components/wifi_provisioning/include/wifi_provisioning/wifi_config.h @@ -17,6 +17,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief WiFi STA status for conveying back to the provisioning master */ @@ -77,6 +81,15 @@ typedef struct { uint8_t channel; /*!< Channel of the AP */ } wifi_prov_config_set_data_t; +/** + * @brief Type of context data passed to each get/set/apply handler + * function set in `wifi_prov_config_handlers` structure. + * + * This is passed as an opaque pointer, thereby allowing it be defined + * later in application code as per requirements. + */ +typedef struct wifi_prov_ctx wifi_prov_ctx_t; + /** * @brief Internal handlers for receiving and responding to protocomm * requests from master @@ -89,14 +102,16 @@ typedef struct wifi_prov_config_handlers { * Handler function called when connection status * of the slave (in WiFi station mode) is requested */ - esp_err_t (*get_status_handler)(wifi_prov_config_get_data_t *resp_data); + esp_err_t (*get_status_handler)(wifi_prov_config_get_data_t *resp_data, + wifi_prov_ctx_t **ctx); /** * Handler function called when WiFi connection configuration * (eg. AP SSID, password, etc.) of the slave (in WiFi station mode) * is to be set to user provided values */ - esp_err_t (*set_config_handler)(const wifi_prov_config_set_data_t *req_data); + esp_err_t (*set_config_handler)(const wifi_prov_config_set_data_t *req_data, + wifi_prov_ctx_t **ctx); /** * Handler function for applying the configuration that was set in @@ -105,7 +120,12 @@ typedef struct wifi_prov_config_handlers { * updated connection status information when `get_status_handler` is * invoked again by the master. */ - esp_err_t (*apply_config_handler)(void); + esp_err_t (*apply_config_handler)(wifi_prov_ctx_t **ctx); + + /** + * Context pointer to be passed to above handler functions upon invocation + */ + wifi_prov_ctx_t *ctx; } wifi_prov_config_handlers_t; /** @@ -117,4 +137,8 @@ typedef struct wifi_prov_config_handlers { esp_err_t wifi_prov_config_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data); +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/wifi_provisioning/src/wifi_config.c b/components/wifi_provisioning/src/wifi_config.c index 6ce1798a7..09ccc37d5 100644 --- a/components/wifi_provisioning/src/wifi_config.c +++ b/components/wifi_provisioning/src/wifi_config.c @@ -72,7 +72,7 @@ static esp_err_t cmd_get_status_handler(WiFiConfigPayload *req, resp_get_status__init(resp_payload); wifi_prov_config_get_data_t resp_data; - if (h->get_status_handler(&resp_data) == ESP_OK) { + if (h->get_status_handler(&resp_data, &h->ctx) == ESP_OK) { if (resp_data.wifi_state == WIFI_PROV_STA_CONNECTING) { resp_payload->sta_state = WIFI_STATION_STATE__Connecting; resp_payload->state_case = RESP_GET_STATUS__STATE_CONNECTED; @@ -158,7 +158,7 @@ static esp_err_t cmd_set_config_handler(WiFiConfigPayload *req, memcpy(req_data.bssid, req->cmd_set_config->bssid.data, req->cmd_set_config->bssid.len); req_data.channel = req->cmd_set_config->channel; - if (h->set_config_handler(&req_data) == ESP_OK) { + if (h->set_config_handler(&req_data, &h->ctx) == ESP_OK) { resp_payload->status = STATUS__Success; } @@ -185,7 +185,7 @@ static esp_err_t cmd_apply_config_handler(WiFiConfigPayload *req, resp_apply_config__init(resp_payload); - if (h->apply_config_handler() == ESP_OK) { + if (h->apply_config_handler(&h->ctx) == ESP_OK) { resp_payload->status = STATUS__Success; } else { resp_payload->status = STATUS__InvalidArgument; diff --git a/docs/en/api-reference/provisioning/protocomm.rst b/docs/en/api-reference/provisioning/protocomm.rst index 8dc72c50a..3ef0b7e5c 100644 --- a/docs/en/api-reference/provisioning/protocomm.rst +++ b/docs/en/api-reference/provisioning/protocomm.rst @@ -54,8 +54,13 @@ For complete example see :example:`provisioning/softap_prov` { protocomm_t *pc = protocomm_new(); + /* Config for protocomm_httpd_start() */ - protocomm_httpd_config_t pc_config = PROTOCOMM_HTTPD_DEFAULT_CONFIG(); + protocomm_httpd_config_t pc_config = { + .data = { + .config = PROTOCOMM_HTTPD_DEFAULT_CONFIG() + } + }; /* Start protocomm server on top of HTTP */ protocomm_httpd_start(pc, &pc_config); diff --git a/docs/en/api-reference/provisioning/wifi_provisioning.rst b/docs/en/api-reference/provisioning/wifi_provisioning.rst index a822bf62f..7f78ee583 100644 --- a/docs/en/api-reference/provisioning/wifi_provisioning.rst +++ b/docs/en/api-reference/provisioning/wifi_provisioning.rst @@ -4,7 +4,9 @@ Wi-Fi Provisioning Overview -------- -This component provides protocomm endpoint handler - `wifi_prov_config_data_handler` - and related protobuf framework which can be used for Wi-Fi configuration in the context of device provisioning, though it may be used in non-provisioning cases as well. The configuration consists of three commands : +This component provides protocomm endpoint handler - `wifi_prov_config_data_handler` - and related protobuf framework which can be used for Wi-Fi configuration in the context of device provisioning, though it may be used in non-provisioning cases as well. + +The configuration consists of three commands : * `get_status` - For querying the Wi-Fi connection status * `set_config` - For setting the Wi-Fi connection credentials * `apply_config` - For applying the credentials saved during `set_config` and (re)start the Wi-Fi station @@ -18,7 +20,7 @@ Application Example :: - esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) + esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx) { /* Fill the wifi_prov_config_get_data_t structure * with Wi-Fi station connection status information. */ @@ -26,7 +28,7 @@ Application Example return ESP_OK; } - esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) + esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx) { /* Copy contents of req_data->ssid and req_data->password * which are Wi-Fi AP credentials to which the device will connect */ @@ -34,7 +36,7 @@ Application Example return ESP_OK; } - esp_err_t apply_config_handler(void) + esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx) { /* Apply the Wi-Fi STA credentials saved during set_config */ @@ -47,6 +49,7 @@ Application Example .get_status_handler = get_status_handler, .set_config_handler = set_config_handler, .apply_config_handler = apply_config_handler, + .ctx = NULL }; /* Set the endpoint handler */ diff --git a/examples/provisioning/ble_prov/main/app_prov.c b/examples/provisioning/ble_prov/main/app_prov.c index b574513ce..1f927dca8 100644 --- a/examples/provisioning/ble_prov/main/app_prov.c +++ b/examples/provisioning/ble_prov/main/app_prov.c @@ -188,7 +188,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event) case SYSTEM_EVENT_STA_GOT_IP: ESP_LOGI(TAG, "STA Got IP"); - /* Station got IP. That means configuraion is successful. + /* Station got IP. That means configuration is successful. * Schedule timer to stop provisioning app after 30 seconds. */ g_prov->wifi_state = WIFI_PROV_STA_CONNECTED; if (g_prov && g_prov->timer) { @@ -341,7 +341,7 @@ esp_err_t app_prov_start_ble_provisioning(int security, const protocomm_security return ESP_ERR_NO_MEM; } - /* Initialise app data */ + /* Initialize app data */ g_prov->pop = pop; g_prov->security = security; diff --git a/examples/provisioning/ble_prov/main/app_prov_handlers.c b/examples/provisioning/ble_prov/main/app_prov_handlers.c index ca6726949..4a0c0d99a 100644 --- a/examples/provisioning/ble_prov/main/app_prov_handlers.c +++ b/examples/provisioning/ble_prov/main/app_prov_handlers.c @@ -1,4 +1,4 @@ -/* BLE based Provisioning Example +/* SoftAP based Provisioning Example This example code is in the Public Domain (or CC0 licensed, at your option.) @@ -23,9 +23,32 @@ static const char* TAG = "app_prov_handler"; -static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) +/* Provide definition of wifi_prov_ctx_t */ +struct wifi_prov_ctx { + wifi_config_t wifi_cfg; +}; + +static wifi_config_t *get_config(wifi_prov_ctx_t **ctx) { - /* Initialise to zero */ + return (*ctx ? &(*ctx)->wifi_cfg : NULL); +} + +static wifi_config_t *new_config(wifi_prov_ctx_t **ctx) +{ + free(*ctx); + (*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t)); + return get_config(ctx); +} + +static void free_config(wifi_prov_ctx_t **ctx) +{ + free(*ctx); + *ctx = NULL; +} + +static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx) +{ + /* Initialize to zero */ memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t)); if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) { @@ -60,16 +83,14 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) return ESP_OK; } -static wifi_config_t *wifi_cfg; - -static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) +static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx) { + wifi_config_t *wifi_cfg = get_config(ctx); if (wifi_cfg) { - free(wifi_cfg); - wifi_cfg = NULL; + free_config(ctx); } - wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t)); + wifi_cfg = new_config(ctx); if (!wifi_cfg) { ESP_LOGE(TAG, "Unable to alloc wifi config"); return ESP_FAIL; @@ -84,8 +105,9 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) return ESP_OK; } -static esp_err_t apply_config_handler(void) +static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx) { + wifi_config_t *wifi_cfg = get_config(ctx); if (!wifi_cfg) { ESP_LOGE(TAG, "WiFi config not set"); return ESP_FAIL; @@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void) app_prov_configure_sta(wifi_cfg); ESP_LOGI(TAG, "WiFi Credentials Applied"); - free(wifi_cfg); - wifi_cfg = NULL; + free_config(ctx); return ESP_OK; } @@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = { .get_status_handler = get_status_handler, .set_config_handler = set_config_handler, .apply_config_handler = apply_config_handler, + .ctx = NULL }; diff --git a/examples/provisioning/console_prov/main/app_prov.c b/examples/provisioning/console_prov/main/app_prov.c index 7eccb8b5f..83c4e4e05 100644 --- a/examples/provisioning/console_prov/main/app_prov.c +++ b/examples/provisioning/console_prov/main/app_prov.c @@ -101,8 +101,8 @@ static void app_prov_stop_service(void) protocomm_delete(g_prov->pc); } -/* Callback to be invoked by timer */ -static void _stop_prov_cb(void * arg) +/* Task spawned by timer callback */ +static void stop_prov_task(void * arg) { ESP_LOGI(TAG, "Stopping provisioning"); app_prov_stop_service(); @@ -116,6 +116,14 @@ static void _stop_prov_cb(void * arg) free(g_prov); g_prov = NULL; ESP_LOGI(TAG, "Provisioning stopped"); + + vTaskDelete(NULL); +} + +/* Callback to be invoked by timer */ +static void _stop_prov_cb(void * arg) +{ + xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL); } /* Event handler for starting/stopping provisioning. @@ -146,7 +154,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event) case SYSTEM_EVENT_STA_GOT_IP: ESP_LOGI(TAG, "STA Got IP"); - /* Station got IP. That means configuraion is successful. + /* Station got IP. That means configuration is successful. * Schedule timer to stop provisioning app after 30 seconds. */ g_prov->wifi_state = WIFI_PROV_STA_CONNECTED; if (g_prov && g_prov->timer) { @@ -299,7 +307,7 @@ esp_err_t app_prov_start_console_provisioning(int security, const protocomm_secu return ESP_ERR_NO_MEM; } - /* Initialise app data */ + /* Initialize app data */ g_prov->pop = pop; g_prov->security = security; @@ -308,7 +316,7 @@ esp_err_t app_prov_start_console_provisioning(int security, const protocomm_secu .callback = _stop_prov_cb, .arg = NULL, .dispatch_method = ESP_TIMER_TASK, - .name = "stop_softap_tm" + .name = "stop_console_tm" }; esp_err_t err = esp_timer_create(&timer_conf, &g_prov->timer); if (err != ESP_OK) { diff --git a/examples/provisioning/console_prov/main/app_prov_handlers.c b/examples/provisioning/console_prov/main/app_prov_handlers.c index 55d2f2c19..49c29739f 100644 --- a/examples/provisioning/console_prov/main/app_prov_handlers.c +++ b/examples/provisioning/console_prov/main/app_prov_handlers.c @@ -23,9 +23,32 @@ static const char* TAG = "app_prov_handler"; -static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) +/* Provide definition of wifi_prov_ctx_t */ +struct wifi_prov_ctx { + wifi_config_t wifi_cfg; +}; + +static wifi_config_t *get_config(wifi_prov_ctx_t **ctx) { - /* Initialise to zero */ + return (*ctx ? &(*ctx)->wifi_cfg : NULL); +} + +static wifi_config_t *new_config(wifi_prov_ctx_t **ctx) +{ + free(*ctx); + (*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t)); + return get_config(ctx); +} + +static void free_config(wifi_prov_ctx_t **ctx) +{ + free(*ctx); + *ctx = NULL; +} + +static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx) +{ + /* Initialize to zero */ memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t)); if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) { @@ -60,16 +83,14 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) return ESP_OK; } -static wifi_config_t *wifi_cfg; - -static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) +static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx) { + wifi_config_t *wifi_cfg = get_config(ctx); if (wifi_cfg) { - free(wifi_cfg); - wifi_cfg = NULL; + free_config(ctx); } - wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t)); + wifi_cfg = new_config(ctx); if (!wifi_cfg) { ESP_LOGE(TAG, "Unable to alloc wifi config"); return ESP_FAIL; @@ -84,8 +105,9 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) return ESP_OK; } -static esp_err_t apply_config_handler(void) +static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx) { + wifi_config_t *wifi_cfg = get_config(ctx); if (!wifi_cfg) { ESP_LOGE(TAG, "WiFi config not set"); return ESP_FAIL; @@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void) app_prov_configure_sta(wifi_cfg); ESP_LOGI(TAG, "WiFi Credentials Applied"); - free(wifi_cfg); - wifi_cfg = NULL; + free_config(ctx); return ESP_OK; } @@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = { .get_status_handler = get_status_handler, .set_config_handler = set_config_handler, .apply_config_handler = apply_config_handler, + .ctx = NULL }; diff --git a/examples/provisioning/custom_config/main/app_prov.c b/examples/provisioning/custom_config/main/app_prov.c index ce33ac960..6ed3df19a 100644 --- a/examples/provisioning/custom_config/main/app_prov.c +++ b/examples/provisioning/custom_config/main/app_prov.c @@ -58,7 +58,11 @@ static esp_err_t app_prov_start_service(void) } /* Config for protocomm_httpd_start() */ - protocomm_httpd_config_t pc_config = PROTOCOMM_HTTPD_DEFAULT_CONFIG(); + protocomm_httpd_config_t pc_config = { + .data = { + .config = PROTOCOMM_HTTPD_DEFAULT_CONFIG() + } + }; /* Start protocomm server on top of HTTP */ if (protocomm_httpd_start(g_prov->pc, &pc_config) != ESP_OK) { @@ -112,8 +116,8 @@ static void app_prov_stop_service(void) protocomm_delete(g_prov->pc); } -/* Callback to be invoked by timer */ -static void _stop_softap_cb(void * arg) +/* Task spawned by timer callback */ +static void stop_prov_task(void * arg) { ESP_LOGI(TAG, "Stopping provisioning"); app_prov_stop_service(); @@ -128,6 +132,14 @@ static void _stop_softap_cb(void * arg) free(g_prov); g_prov = NULL; ESP_LOGI(TAG, "Provisioning stopped"); + + vTaskDelete(NULL); +} + +/* Callback to be invoked by timer */ +static void _stop_prov_cb(void * arg) +{ + xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL); } /* Event handler for starting/stopping provisioning. @@ -158,7 +170,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event) case SYSTEM_EVENT_STA_GOT_IP: ESP_LOGI(TAG, "STA Got IP"); - /* Station got IP. That means configuraion is successful. + /* Station got IP. That means configuration is successful. * Schedule timer to stop provisioning app after 30 seconds. */ g_prov->wifi_state = WIFI_PROV_STA_CONNECTED; if (g_prov && g_prov->timer) { @@ -170,7 +182,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event) * to reconnect and get STA connection status from the device. * Otherwise, the AP will be turned off before the user can * reconnect and thus the user app will see connection timed out, - * signalling a failure in provisioning. */ + * signaling a failure in provisioning. */ esp_timer_start_once(g_prov->timer, 30000*1000U); } break; @@ -299,7 +311,7 @@ esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg) static esp_err_t start_wifi_ap(const char *ssid, const char *pass) { - /* Initialise WiFi with default configuration */ + /* Initialize WiFi with default configuration */ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_err_t err = esp_wifi_init(&cfg); if (err != ESP_OK) { @@ -368,7 +380,7 @@ esp_err_t app_prov_start_softap_provisioning(const char *ssid, const char *pass, /* Create timer object as a member of app data */ esp_timer_create_args_t timer_conf = { - .callback = _stop_softap_cb, + .callback = _stop_prov_cb, .arg = NULL, .dispatch_method = ESP_TIMER_TASK, .name = "stop_softap_tm" diff --git a/examples/provisioning/custom_config/main/app_prov_handlers.c b/examples/provisioning/custom_config/main/app_prov_handlers.c index 14dec260b..c67eeebca 100644 --- a/examples/provisioning/custom_config/main/app_prov_handlers.c +++ b/examples/provisioning/custom_config/main/app_prov_handlers.c @@ -24,6 +24,29 @@ static const char* TAG = "app_prov_handler"; +/* Provide definition of wifi_prov_ctx_t */ +struct wifi_prov_ctx { + wifi_config_t wifi_cfg; +}; + +static wifi_config_t *get_config(wifi_prov_ctx_t **ctx) +{ + return (*ctx ? &(*ctx)->wifi_cfg : NULL); +} + +static wifi_config_t *new_config(wifi_prov_ctx_t **ctx) +{ + free(*ctx); + (*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t)); + return get_config(ctx); +} + +static void free_config(wifi_prov_ctx_t **ctx) +{ + free(*ctx); + *ctx = NULL; +} + /****************** Handler for Custom Configuration *******************/ static esp_err_t custom_config_handler(const custom_config_t *config) { @@ -35,9 +58,9 @@ static esp_err_t custom_config_handler(const custom_config_t *config) custom_prov_config_handler_t custom_prov_handler = custom_config_handler; /****************** Handlers for Wi-Fi Configuration *******************/ -static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) +static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx) { - /* Initialise to zero */ + /* Initialize to zero */ memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t)); if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) { @@ -72,16 +95,14 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) return ESP_OK; } -static wifi_config_t *wifi_cfg; - -static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) +static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx) { + wifi_config_t *wifi_cfg = get_config(ctx); if (wifi_cfg) { - free(wifi_cfg); - wifi_cfg = NULL; + free_config(ctx); } - wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t)); + wifi_cfg = new_config(ctx); if (!wifi_cfg) { ESP_LOGE(TAG, "Unable to alloc wifi config"); return ESP_FAIL; @@ -96,8 +117,9 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) return ESP_OK; } -static esp_err_t apply_config_handler(void) +static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx) { + wifi_config_t *wifi_cfg = get_config(ctx); if (!wifi_cfg) { ESP_LOGE(TAG, "WiFi config not set"); return ESP_FAIL; @@ -106,8 +128,7 @@ static esp_err_t apply_config_handler(void) app_prov_configure_sta(wifi_cfg); ESP_LOGI(TAG, "WiFi Credentials Applied"); - free(wifi_cfg); - wifi_cfg = NULL; + free_config(ctx); return ESP_OK; } @@ -115,4 +136,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = { .get_status_handler = get_status_handler, .set_config_handler = set_config_handler, .apply_config_handler = apply_config_handler, + .ctx = NULL }; diff --git a/examples/provisioning/softap_prov/main/app_prov.c b/examples/provisioning/softap_prov/main/app_prov.c index b110d2e52..79c1e0da0 100644 --- a/examples/provisioning/softap_prov/main/app_prov.c +++ b/examples/provisioning/softap_prov/main/app_prov.c @@ -56,8 +56,11 @@ static esp_err_t app_prov_start_service(void) } /* Config for protocomm_httpd_start() */ - protocomm_httpd_config_t pc_config = PROTOCOMM_HTTPD_DEFAULT_CONFIG(); - + protocomm_httpd_config_t pc_config = { + .data = { + .config = PROTOCOMM_HTTPD_DEFAULT_CONFIG() + } + }; /* Start protocomm server on top of HTTP */ if (protocomm_httpd_start(g_prov->pc, &pc_config) != ESP_OK) { ESP_LOGE(TAG, "Failed to start protocomm HTTP server"); @@ -99,8 +102,8 @@ static void app_prov_stop_service(void) protocomm_delete(g_prov->pc); } -/* Callback to be invoked by timer */ -static void _stop_softap_cb(void * arg) +/* Task spawned by timer callback */ +static void stop_prov_task(void * arg) { ESP_LOGI(TAG, "Stopping provisioning"); app_prov_stop_service(); @@ -115,6 +118,14 @@ static void _stop_softap_cb(void * arg) free(g_prov); g_prov = NULL; ESP_LOGI(TAG, "Provisioning stopped"); + + vTaskDelete(NULL); +} + +/* Callback to be invoked by timer */ +static void _stop_prov_cb(void * arg) +{ + xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL); } /* Event handler for starting/stopping provisioning. @@ -145,7 +156,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event) case SYSTEM_EVENT_STA_GOT_IP: ESP_LOGI(TAG, "STA Got IP"); - /* Station got IP. That means configuraion is successful. + /* Station got IP. That means configuration is successful. * Schedule timer to stop provisioning app after 30 seconds. */ g_prov->wifi_state = WIFI_PROV_STA_CONNECTED; if (g_prov && g_prov->timer) { @@ -157,7 +168,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event) * to reconnect and get STA connection status from the device. * Otherwise, the AP will be turned off before the user can * reconnect and thus the user app will see connection timed out, - * signalling a failure in provisioning. */ + * signaling a failure in provisioning. */ esp_timer_start_once(g_prov->timer, 30000*1000U); } break; @@ -287,7 +298,7 @@ esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg) static esp_err_t start_wifi_ap(const char *ssid, const char *pass) { - /* Initialise WiFi with default configuration */ + /* Initialize WiFi with default configuration */ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_err_t err = esp_wifi_init(&cfg); if (err != ESP_OK) { @@ -350,13 +361,13 @@ esp_err_t app_prov_start_softap_provisioning(const char *ssid, const char *pass, return ESP_ERR_NO_MEM; } - /* Initialise app data */ + /* Initialize app data */ g_prov->pop = pop; g_prov->security = security; /* Create timer object as a member of app data */ esp_timer_create_args_t timer_conf = { - .callback = _stop_softap_cb, + .callback = _stop_prov_cb, .arg = NULL, .dispatch_method = ESP_TIMER_TASK, .name = "stop_softap_tm" diff --git a/examples/provisioning/softap_prov/main/app_prov_handlers.c b/examples/provisioning/softap_prov/main/app_prov_handlers.c index c9704576c..4a0c0d99a 100644 --- a/examples/provisioning/softap_prov/main/app_prov_handlers.c +++ b/examples/provisioning/softap_prov/main/app_prov_handlers.c @@ -23,9 +23,32 @@ static const char* TAG = "app_prov_handler"; -static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) +/* Provide definition of wifi_prov_ctx_t */ +struct wifi_prov_ctx { + wifi_config_t wifi_cfg; +}; + +static wifi_config_t *get_config(wifi_prov_ctx_t **ctx) { - /* Initialise to zero */ + return (*ctx ? &(*ctx)->wifi_cfg : NULL); +} + +static wifi_config_t *new_config(wifi_prov_ctx_t **ctx) +{ + free(*ctx); + (*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t)); + return get_config(ctx); +} + +static void free_config(wifi_prov_ctx_t **ctx) +{ + free(*ctx); + *ctx = NULL; +} + +static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx) +{ + /* Initialize to zero */ memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t)); if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) { @@ -60,16 +83,14 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data) return ESP_OK; } -static wifi_config_t *wifi_cfg; - -static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) +static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx) { + wifi_config_t *wifi_cfg = get_config(ctx); if (wifi_cfg) { - free(wifi_cfg); - wifi_cfg = NULL; + free_config(ctx); } - wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t)); + wifi_cfg = new_config(ctx); if (!wifi_cfg) { ESP_LOGE(TAG, "Unable to alloc wifi config"); return ESP_FAIL; @@ -84,8 +105,9 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data) return ESP_OK; } -static esp_err_t apply_config_handler(void) +static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx) { + wifi_config_t *wifi_cfg = get_config(ctx); if (!wifi_cfg) { ESP_LOGE(TAG, "WiFi config not set"); return ESP_FAIL; @@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void) app_prov_configure_sta(wifi_cfg); ESP_LOGI(TAG, "WiFi Credentials Applied"); - free(wifi_cfg); - wifi_cfg = NULL; + free_config(ctx); return ESP_OK; } @@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = { .get_status_handler = get_status_handler, .set_config_handler = set_config_handler, .apply_config_handler = apply_config_handler, + .ctx = NULL }; diff --git a/tools/esp_prov/esp_prov.py b/tools/esp_prov/esp_prov.py index 10ad67134..0ea172da5 100644 --- a/tools/esp_prov/esp_prov.py +++ b/tools/esp_prov/esp_prov.py @@ -59,7 +59,7 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None): def version_match(tp, protover): try: response = tp.send_data('proto-ver', protover) - if response != "SUCCESS": + if response != protover: return False return True except RuntimeError as e: