Merge branch 'feature/wifi_provisioning_handler_ctx' into 'master'

Provisioning : Various fixes in protocomm and wifi_provisioning components

See merge request idf/esp-idf!4188
This commit is contained in:
Angus Gratton 2019-02-18 08:06:12 +08:00
commit bcc21d2262
29 changed files with 519 additions and 240 deletions

View file

@ -17,6 +17,10 @@
#include <protocomm_security.h> #include <protocomm_security.h>
#include <esp_err.h> #include <esp_err.h>
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* @brief Function prototype for protocomm endpoint handler * @brief Function prototype for protocomm endpoint handler
*/ */
@ -42,7 +46,7 @@ typedef struct protocomm protocomm_t;
* @brief Create a new protocomm instance * @brief Create a new protocomm instance
* *
* This API will return a new dynamically allocated 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 * @return
* - protocomm_t* : On success * - protocomm_t* : On success
@ -71,7 +75,8 @@ void protocomm_delete(protocomm_t *pc);
* - An endpoint must be bound to a valid protocomm instance, * - An endpoint must be bound to a valid protocomm instance,
* created using `protocomm_new()`. * created using `protocomm_new()`.
* - This function internally calls the registered `add_endpoint()` * - 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] pc Pointer to the protocomm instance
* @param[in] ep_name Endpoint identifier(name) string * @param[in] ep_name Endpoint identifier(name) string
@ -81,7 +86,7 @@ void protocomm_delete(protocomm_t *pc);
* Pass NULL if not needed. * Pass NULL if not needed.
* *
* @return * @return
* - ESP_OK : Added new endpoint succesfully * - ESP_OK : Success
* - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists * - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists
* - ESP_ERR_NO_MEM : Error allocating endpoint resource * - ESP_ERR_NO_MEM : Error allocating endpoint resource
* - ESP_ERR_INVALID_ARG : Null instance/name/handler arguments * - 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 * @param[in] ep_name Endpoint identifier(name) string
* *
* @return * @return
* - ESP_OK : Added new endpoint succesfully * - ESP_OK : Success
* - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist * - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist
* - ESP_ERR_INVALID_ARG : Null instance/name arguments * - 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 * @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 * @note
* - An endpoint must be bound to a valid protocomm instance, * - An endpoint must be bound to a valid protocomm instance,
* created using `protocomm_new()`. * 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] pc Pointer to the protocomm instance
* @param[in] ep_name Endpoint identifier(name) string * @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 * @param[out] outlen Buffer length of the allocated output buffer
* *
* @return * @return
* - ESP_OK : Request handled succesfully * - ESP_OK : Request handled successfully
* - ESP_FAIL : Internal error in execution of registered handler * - ESP_FAIL : Internal error in execution of registered handler
* - ESP_ERR_NO_MEM : Error allocating internal resource * - ESP_ERR_NO_MEM : Error allocating internal resource
* - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist * - 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 * @param[in] pop Pointer to proof of possession for authenticating a client
* *
* @return * @return
* - ESP_OK : Added new security endpoint succesfully * - ESP_OK : Success
* - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists * - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists
* - ESP_ERR_INVALID_STATE : Security endpoint already set * - ESP_ERR_INVALID_STATE : Security endpoint already set
* - ESP_ERR_NO_MEM : Error allocating endpoint resource * - 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 * @param[in] ep_name Endpoint identifier(name) string
* *
* @return * @return
* - ESP_OK : Added new endpoint succesfully * - ESP_OK : Success
* - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist * - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist
* - ESP_ERR_INVALID_ARG : Null instance/name arguments * - 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 * @brief Set endpoint for version verification
* *
* This API can be used for setting an application specific protocol * 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 * @note
* - An endpoint must be bound to a valid protocomm instance, * - 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 * @param[in] version Version identifier(name) string
* *
* @return * @return
* - ESP_OK : Added new security endpoint succesfully * - ESP_OK : Success
* - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists * - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists
* - ESP_ERR_INVALID_STATE : Version endpoint already set * - ESP_ERR_INVALID_STATE : Version endpoint already set
* - ESP_ERR_NO_MEM : Error allocating endpoint resource * - 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 * @param[in] ep_name Endpoint identifier(name) string
* *
* @return * @return
* - ESP_OK : Added new endpoint succesfully * - ESP_OK : Success
* - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist * - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist
* - ESP_ERR_INVALID_ARG : Null instance/name arguments * - ESP_ERR_INVALID_ARG : Null instance/name arguments
*/ */
esp_err_t protocomm_unset_version(protocomm_t *pc, const char *ep_name); esp_err_t protocomm_unset_version(protocomm_t *pc, const char *ep_name);
#ifdef __cplusplus
}
#endif

View file

@ -16,6 +16,10 @@
#include <esp_err.h> #include <esp_err.h>
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* @brief Proof Of Possession for authenticating a secure session * @brief Proof Of Possession for authenticating a secure session
*/ */
@ -42,12 +46,12 @@ typedef struct protocomm_security_pop {
*/ */
typedef struct protocomm_security { typedef struct protocomm_security {
/** /**
* Unique version number of security implmentation * Unique version number of security implementation
*/ */
int ver; int ver;
/** /**
* Function for initialising/allocating security * Function for initializing/allocating security
* infrastructure * infrastructure
*/ */
esp_err_t (*init)(); esp_err_t (*init)();
@ -91,3 +95,7 @@ typedef struct protocomm_security {
const uint8_t *inbuf, ssize_t inlen, const uint8_t *inbuf, ssize_t inlen,
uint8_t *outbuf, ssize_t *outlen); uint8_t *outbuf, ssize_t *outlen);
} protocomm_security_t; } protocomm_security_t;
#ifdef __cplusplus
}
#endif

View file

@ -16,6 +16,10 @@
#include <protocomm_security.h> #include <protocomm_security.h>
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* @brief Protocomm security version 0 implementation * @brief Protocomm security version 0 implementation
* *
@ -23,3 +27,7 @@
* security is required for the protocomm instance * security is required for the protocomm instance
*/ */
extern const protocomm_security_t protocomm_security0; extern const protocomm_security_t protocomm_security0;
#ifdef __cplusplus
}
#endif

View file

@ -16,10 +16,18 @@
#include <protocomm_security.h> #include <protocomm_security.h>
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* @brief Protocomm security version 1 implementation * @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 * Curve25519 key exchange and AES-256-CTR encryption
*/ */
extern const protocomm_security_t protocomm_security1; extern const protocomm_security_t protocomm_security1;
#ifdef __cplusplus
}
#endif

View file

@ -16,6 +16,10 @@
#include <protocomm.h> #include <protocomm.h>
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* BLE device name cannot be larger than this value * 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 * 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 * UUID to be assigned to the BLE characteristic which is
@ -63,10 +67,10 @@ typedef struct {
* the initialization for characteristics/service for BLE. * the initialization for characteristics/service for BLE.
* *
* @param[in] pc Protocomm instance pointer obtained from protocomm_new() * @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 * @return
* - ESP_OK : if successful * - ESP_OK : Success
* - ESP_FAIL : Simple BLE start error * - ESP_FAIL : Simple BLE start error
* - ESP_ERR_NO_MEM : Error allocating memory for internal resources * - ESP_ERR_NO_MEM : Error allocating memory for internal resources
* - ESP_ERR_INVALID_STATE : Error in ble config * - 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() * @param[in] pc Same protocomm instance that was passed to protocomm_ble_start()
* *
* @return * @return
* - ESP_OK : For success or appropriate error code * - ESP_OK : Success
* - ESP_FAIL : Simple BLE stop error * - ESP_FAIL : Simple BLE stop error
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance * - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance
*/ */
esp_err_t protocomm_ble_stop(protocomm_t *pc); esp_err_t protocomm_ble_stop(protocomm_t *pc);
#ifdef __cplusplus
}
#endif

View file

@ -16,6 +16,10 @@
#include <protocomm.h> #include <protocomm.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PROTOCOMM_CONSOLE_DEFAULT_CONFIG() { \ #define PROTOCOMM_CONSOLE_DEFAULT_CONFIG() { \
.stack_size = 4096, \ .stack_size = 4096, \
.task_priority = tskIDLE_PRIORITY + 3, \ .task_priority = tskIDLE_PRIORITY + 3, \
@ -25,7 +29,7 @@
* @brief Config parameters for protocomm console * @brief Config parameters for protocomm console
*/ */
typedef struct { 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 */ unsigned task_priority; /*!< Priority of console task */
} protocomm_console_config_t; } protocomm_console_config_t;
@ -39,7 +43,7 @@ typedef struct {
* @param[in] config Config param structure for protocomm console * @param[in] config Config param structure for protocomm console
* *
* @return * @return
* - ESP_OK : Server started succefully * - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null arguments * - ESP_ERR_INVALID_ARG : Null arguments
* - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance * - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance
* - ESP_ERR_INVALID_STATE : Transport layer already bound to this 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() * @param[in] pc Same protocomm instance that was passed to protocomm_console_start()
* *
* @return * @return
* - ESP_OK : Server stopped succefully * - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer * - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer
*/ */
esp_err_t protocomm_console_stop(protocomm_t *pc); esp_err_t protocomm_console_stop(protocomm_t *pc);
#ifdef __cplusplus
}
#endif

View file

@ -22,12 +22,16 @@
.task_priority = tskIDLE_PRIORITY + 5, \ .task_priority = tskIDLE_PRIORITY + 5, \
} }
#ifdef __cplusplus
extern "C" {
#endif
/**
/** Protocomm HTTP Server Configuration */ * @brief Config parameters for protocomm HTTP server
*/
typedef struct { 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 * Stack size of server task, adjusted depending
@ -37,11 +41,15 @@ typedef struct {
unsigned task_priority; /*!< Priority of server task */ unsigned task_priority; /*!< Priority of server task */
} protocomm_http_server_config_t; /*!< HTTP Server Configuration, if HTTP Server has not been started already */ } protocomm_http_server_config_t; /*!< HTTP Server Configuration, if HTTP Server has not been started already */
/** Protocomm HTTPD Configuration Data */ /** Protocomm HTTPD Configuration Data
*/
typedef union { typedef union {
/** HTTP Server Handle, if ext_handle_provided is set to true */ /** HTTP Server Handle, if ext_handle_provided is set to true
*/
void *handle; void *handle;
/** HTTP Server Configuration, if a server is not already active */
/** HTTP Server Configuration, if a server is not already active
*/
protocomm_http_server_config_t config; protocomm_http_server_config_t config;
} protocomm_httpd_config_data_t; } protocomm_httpd_config_data_t;
@ -68,10 +76,10 @@ typedef struct {
* one instance can be bound to an HTTP transport layer. * one instance can be bound to an HTTP transport layer.
* *
* @param[in] pc Protocomm instance pointer obtained from protocomm_new() * @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 * @return
* - ESP_OK : Server started succefully * - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null arguments * - ESP_ERR_INVALID_ARG : Null arguments
* - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance * - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance
* - ESP_ERR_INVALID_STATE : Transport layer already bound to this protocomm instance * - ESP_ERR_INVALID_STATE : Transport layer already bound to this protocomm instance
@ -89,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() * @param[in] pc Same protocomm instance that was passed to protocomm_httpd_start()
* *
* @return * @return
* - ESP_OK : Server stopped succefully * - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer * - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer
*/ */
esp_err_t protocomm_httpd_stop(protocomm_t *pc); esp_err_t protocomm_httpd_stop(protocomm_t *pc);
#ifdef __cplusplus
}
#endif

View file

@ -52,6 +52,19 @@ void protocomm_delete(protocomm_t *pc)
free(it); 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); 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, const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen) 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); ESP_LOGE(TAG, "Invalid params %p %p", pc, ep_name);
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
*outbuf = NULL;
*outlen = 0;
protocomm_ep_t *ep = search_endpoint(pc, ep_name); protocomm_ep_t *ep = search_endpoint(pc, ep_name);
if (!ep) { if (!ep) {
ESP_LOGE(TAG, "No registered endpoint for %s", ep_name); 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; 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 */ /* Invoke the request handler */
uint8_t *plaintext_resp; uint8_t *plaintext_resp = NULL;
ssize_t plaintext_resp_len; ssize_t plaintext_resp_len = 0;
ret = ep->req_handler(session_id, ret = ep->req_handler(session_id,
dec_inbuf, dec_inbuf_len, dec_inbuf, dec_inbuf_len,
&plaintext_resp, &plaintext_resp_len, &plaintext_resp, &plaintext_resp_len,
ep->priv_data); ep->priv_data);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Request handler for %s failed", ep_name); ESP_LOGE(TAG, "Request handler for %s failed", ep_name);
*outbuf = NULL; free(plaintext_resp);
*outlen = 0;
free(dec_inbuf); free(dec_inbuf);
return ret; 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); uint8_t *enc_resp = (uint8_t *) malloc(plaintext_resp_len);
if (!enc_resp) { if (!enc_resp) {
ESP_LOGE(TAG, "Failed to allocate decrypt buf len %d", inlen); ESP_LOGE(TAG, "Failed to allocate decrypt buf len %d", inlen);
free(plaintext_resp);
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
ssize_t enc_resp_len = plaintext_resp_len; ssize_t enc_resp_len = plaintext_resp_len;
pc->sec->encrypt(session_id, plaintext_resp, plaintext_resp_len, ret = pc->sec->encrypt(session_id, plaintext_resp, plaintext_resp_len,
enc_resp, &enc_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 */ /* We no more need plaintext response */
free(plaintext_resp); free(plaintext_resp);
@ -257,7 +285,7 @@ esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name,
if (sec->init) { if (sec->init) {
ret = sec->init(); ret = sec->init();
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Error initialising security"); ESP_LOGE(TAG, "Error initializing security");
protocomm_remove_endpoint(pc, ep_name); protocomm_remove_endpoint(pc, ep_name);
return ret; return ret;
} }
@ -305,40 +333,22 @@ static int protocomm_version_handler(uint32_t session_id,
uint8_t **outbuf, ssize_t *outlen, uint8_t **outbuf, ssize_t *outlen,
void *priv_data) 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; protocomm_t *pc = (protocomm_t *) priv_data;
*outbuf = NULL; if (!pc->ver) {
*outlen = 0; *outlen = 0;
*outbuf = NULL;
if ((pc->ver != NULL) && (version != NULL)) { return ESP_OK;
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;
} }
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 */ /* Output is a non null terminated string with length specified */
*outlen = strlen(result_msg); *outlen = strlen(pc->ver);
*outbuf = malloc(strlen(result_msg)); *outbuf = malloc(*outlen);
if (outbuf == NULL) { 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; return ESP_ERR_NO_MEM;
} }
memcpy(*outbuf, result_msg, *outlen); memcpy(*outbuf, pc->ver, *outlen);
return ESP_OK; return ESP_OK;
} }

View file

@ -62,7 +62,7 @@ struct protocomm {
int (*remove_endpoint)(const char *ep_name); int (*remove_endpoint)(const char *ep_name);
/* Pointer to security layer instance to be used internally for /* Pointer to security layer instance to be used internally for
* establising secure sessions */ * establishing secure sessions */
const protocomm_security_t *sec; const protocomm_security_t *sec;
/* Pointer to proof of possession object */ /* Pointer to proof of possession object */

View file

@ -36,6 +36,8 @@ static esp_err_t sec0_session_setup(uint32_t session_id,
S0SessionResp *s0resp = (S0SessionResp *) malloc(sizeof(S0SessionResp)); S0SessionResp *s0resp = (S0SessionResp *) malloc(sizeof(S0SessionResp));
if (!out || !s0resp) { if (!out || !s0resp) {
ESP_LOGE(TAG, "Error allocating response"); ESP_LOGE(TAG, "Error allocating response");
free(out);
free(s0resp);
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
sec0_payload__init(out); 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) { if (req->sec_ver != protocomm_security0.ver) {
ESP_LOGE(TAG, "Security version mismatch. Closing connection"); ESP_LOGE(TAG, "Security version mismatch. Closing connection");
session_data__free_unpacked(req, NULL);
return ESP_ERR_INVALID_ARG; 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); ret = sec0_session_setup(session_id, req, &resp, pop);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Session setup error %d", ret); ESP_LOGE(TAG, "Session setup error %d", ret);
session_data__free_unpacked(req, NULL);
return ESP_FAIL; return ESP_FAIL;
} }
session_data__free_unpacked(req, NULL);
resp.sec_ver = req->sec_ver; resp.sec_ver = req->sec_ver;
session_data__free_unpacked(req, NULL);
*outlen = session_data__get_packed_size(&resp); *outlen = session_data__get_packed_size(&resp);
*outbuf = (uint8_t *) malloc(*outlen); *outbuf = (uint8_t *) malloc(*outlen);

View file

@ -38,8 +38,9 @@ static const char* TAG = "security1";
#define PUBLIC_KEY_LEN 32 #define PUBLIC_KEY_LEN 32
#define SZ_RANDOM 16 #define SZ_RANDOM 16
#define SESSION_STATE_1 1 /* Session in state 1 */ #define SESSION_STATE_CMD0 0 /* Session is not setup */
#define SESSION_STATE_SETUP 2 /* Session setup successful */ #define SESSION_STATE_CMD1 1 /* Session is not setup */
#define SESSION_STATE_DONE 2 /* Session setup successful */
typedef struct session { typedef struct session {
/* Session data */ /* Session data */
@ -82,22 +83,12 @@ static esp_err_t handle_session_command1(uint32_t session_id,
uint8_t check_buf[PUBLIC_KEY_LEN]; uint8_t check_buf[PUBLIC_KEY_LEN];
int mbed_err; int mbed_err;
if (!cur_session) { if (cur_session->state != SESSION_STATE_CMD1) {
ESP_LOGE(TAG, "Data on session endpoint without session establishment"); ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD1, cur_session->state);
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
if (session_id != cur_session->id) { /* Initialize crypto context */
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 */
mbedtls_aes_init(&cur_session->ctx_aes); mbedtls_aes_init(&cur_session->ctx_aes);
memset(cur_session->stb, 0, sizeof(cur_session->stb)); memset(cur_session->stb, 0, sizeof(cur_session->stb));
cur_session->nc_off = 0; 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); sizeof(cur_session->sym_key)*8);
if (mbed_err != 0) { if (mbed_err != 0) {
ESP_LOGE(TAG, "Failure at mbedtls_aes_setkey_enc with error code : -0x%x", -mbed_err); 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; 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); in->sc1->client_verify_data.data, check_buf);
if (mbed_err != 0) { if (mbed_err != 0) {
ESP_LOGE(TAG, "Failure at mbedtls_aes_crypt_ctr with error code : -0x%x", -mbed_err); 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; 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, if (mbedtls_ssl_safer_memcmp(check_buf, cur_session->device_pubkey,
sizeof(cur_session->device_pubkey)) != 0) { sizeof(cur_session->device_pubkey)) != 0) {
ESP_LOGE(TAG, "Key mismatch. Close connection"); ESP_LOGE(TAG, "Key mismatch. Close connection");
mbedtls_aes_free(&cur_session->ctx_aes);
return ESP_FAIL; return ESP_FAIL;
} }
Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload)); Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload));
sec1_payload__init(out);
SessionResp1 *out_resp = (SessionResp1 *) malloc(sizeof(SessionResp1)); 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; out_resp->status = STATUS__Success;
uint8_t *outbuf = (uint8_t *) malloc(PUBLIC_KEY_LEN); uint8_t *outbuf = (uint8_t *) malloc(PUBLIC_KEY_LEN);
if (!outbuf) { if (!outbuf) {
ESP_LOGE(TAG, "Error allocating ciphertext buffer"); ESP_LOGE(TAG, "Error allocating ciphertext buffer");
free(out);
free(out_resp);
mbedtls_aes_free(&cur_session->ctx_aes);
return ESP_ERR_NO_MEM; 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); cur_session->client_pubkey, outbuf);
if (mbed_err != 0) { if (mbed_err != 0) {
ESP_LOGE(TAG, "Failure at mbedtls_aes_crypt_ctr with error code : -0x%x", -mbed_err); 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; 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->proto_case = SESSION_DATA__PROTO_SEC1;
resp->sec1 = out; resp->sec1 = out;
ESP_LOGD(TAG, "Session successful"); cur_session->state = SESSION_STATE_DONE;
ESP_LOGD(TAG, "Secure session established successfully");
return ESP_OK; return ESP_OK;
} }
@ -172,32 +180,21 @@ static esp_err_t handle_session_command0(uint32_t session_id,
SessionData *req, SessionData *resp, SessionData *req, SessionData *resp,
const protocomm_security_pop_t *pop) const protocomm_security_pop_t *pop)
{ {
ESP_LOGD(TAG, "Request to handle setup0_command");
Sec1Payload *in = (Sec1Payload *) req->sec1; Sec1Payload *in = (Sec1Payload *) req->sec1;
esp_err_t ret; esp_err_t ret;
int mbed_err; int mbed_err;
if (!cur_session) { if (cur_session->state != SESSION_STATE_CMD0) {
ESP_LOGE(TAG, "Data on session endpoint without session establishment"); ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD0, cur_session->state);
return ESP_ERR_INVALID_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) { if (in->sc0->client_pubkey.len != PUBLIC_KEY_LEN) {
ESP_LOGE(TAG, "Invalid public key length"); ESP_LOGE(TAG, "Invalid public key length");
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
cur_session->state = SESSION_STATE_1;
mbedtls_ecdh_context *ctx_server = malloc(sizeof(mbedtls_ecdh_context)); mbedtls_ecdh_context *ctx_server = malloc(sizeof(mbedtls_ecdh_context));
mbedtls_entropy_context *entropy = malloc(sizeof(mbedtls_entropy_context)); mbedtls_entropy_context *entropy = malloc(sizeof(mbedtls_entropy_context));
mbedtls_ctr_drbg_context *ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_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)); Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload));
SessionResp0 *out_resp = (SessionResp0 *) malloc(sizeof(SessionResp0)); SessionResp0 *out_resp = (SessionResp0 *) malloc(sizeof(SessionResp0));
if (!out || !out_resp) { if (!out || !out_resp) {
ESP_LOGE(TAG, "Error allocating memory for response"); ESP_LOGE(TAG, "Error allocating memory for response0");
ret = ESP_FAIL; ret = ESP_ERR_NO_MEM;
free(out);
free(out_resp);
goto exit_cmd0; 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->proto_case = SESSION_DATA__PROTO_SEC1;
resp->sec1 = out; resp->sec1 = out;
cur_session->state = SESSION_STATE_CMD1;
ESP_LOGD(TAG, "Session setup phase1 done"); ESP_LOGD(TAG, "Session setup phase1 done");
ret = ESP_OK; ret = ESP_OK;
@ -361,6 +362,21 @@ static esp_err_t sec1_session_setup(uint32_t session_id,
Sec1Payload *in = (Sec1Payload *) req->sec1; Sec1Payload *in = (Sec1Payload *) req->sec1;
esp_err_t ret; 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) { switch (in->msg) {
case SEC1_MSG_TYPE__Session_Command0: case SEC1_MSG_TYPE__Session_Command0:
ret = handle_session_command0(session_id, req, resp, pop); 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; return;
} }
static esp_err_t sec1_init() static esp_err_t sec1_close_session(uint32_t session_id)
{ {
return ESP_OK; if (!cur_session || cur_session->id != session_id) {
} ESP_LOGE(TAG, "Attempt to close invalid session");
return ESP_ERR_INVALID_ARG;
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->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; return ESP_OK;
} }
static esp_err_t sec1_new_session(uint32_t session_id) 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); ESP_LOGE(TAG, "Closing old session with id %u", cur_session->id);
sec1_cleanup(); sec1_close_session(cur_session->id);
} else if (cur_session && cur_session->id == session_id) {
return ESP_OK;
} }
cur_session = (session_t *) calloc(1, sizeof(session_t)); 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; 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) { return ESP_OK;
ESP_LOGE(TAG, "Attempt to close invalid session"); }
return ESP_ERR_INVALID_ARG;
}
bzero(cur_session, sizeof(session_t)); static esp_err_t sec1_cleanup()
free(cur_session); {
cur_session = NULL; if (cur_session) {
ESP_LOGD(TAG, "Closing current session with id %u", cur_session->id);
sec1_close_session(cur_session->id);
}
return ESP_OK; 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) { if (!cur_session || cur_session->id != session_id) {
ESP_LOGE(TAG, "Session with ID %d not found", session_id);
return ESP_ERR_INVALID_STATE; 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; *outlen = inlen;
int ret = mbedtls_aes_crypt_ctr(&cur_session->ctx_aes, inlen, &cur_session->nc_off, int ret = mbedtls_aes_crypt_ctr(&cur_session->ctx_aes, inlen, &cur_session->nc_off,
cur_session->rand, cur_session->stb, inbuf, outbuf); 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) { if (req->sec_ver != protocomm_security1.ver) {
ESP_LOGE(TAG, "Security version mismatch. Closing connection"); ESP_LOGE(TAG, "Security version mismatch. Closing connection");
session_data__free_unpacked(req, NULL);
return ESP_ERR_INVALID_ARG; 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); ret = sec1_session_setup(session_id, req, &resp, pop);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Session setup error %d", ret); ESP_LOGE(TAG, "Session setup error %d", ret);
session_data__free_unpacked(req, NULL);
return ESP_FAIL; return ESP_FAIL;
} }
session_data__free_unpacked(req, NULL);
resp.sec_ver = req->sec_ver; resp.sec_ver = req->sec_ver;
session_data__free_unpacked(req, NULL);
*outlen = session_data__get_packed_size(&resp); *outlen = session_data__get_packed_size(&resp);
*outbuf = (uint8_t *) malloc(*outlen); *outbuf = (uint8_t *) malloc(*outlen);

View file

@ -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); g_ble_cfg_p->exec_write_fn(event, gatts_if, param);
break; break;
case ESP_GATTS_MTU_EVT: 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) { if (g_ble_cfg_p->set_mtu_fn) {
g_ble_cfg_p->set_mtu_fn(event, gatts_if, param); g_ble_cfg_p->set_mtu_fn(event, gatts_if, param);
} }

View file

@ -55,7 +55,7 @@ typedef struct {
} simple_ble_cfg_t; } simple_ble_cfg_t;
/** Initialise a simple ble connection /** Initialize a simple ble connection
* *
* This function allocates memory and returns a pointer to the * This function allocates memory and returns a pointer to the
* configuration structure. * configuration structure.

View file

@ -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) 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_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 && if (protoble_internal->pc_ble->sec &&
protoble_internal->pc_ble->sec->close_transport_session) { protoble_internal->pc_ble->sec->close_transport_session) {
ret = protoble_internal->pc_ble->sec->close_transport_session(param->disconnect.conn_id); 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) 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_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 && if (protoble_internal->pc_ble->sec &&
protoble_internal->pc_ble->sec->new_transport_session) { protoble_internal->pc_ble->sec->new_transport_session) {
ret = protoble_internal->pc_ble->sec->new_transport_session(param->connect.conn_id); 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) { if (protoble_internal->g_nu_lookup) {
for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) { for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) {
if (protoble_internal->g_nu_lookup[i].name) { 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); 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; 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; return ESP_OK;
} }

View file

@ -76,7 +76,7 @@ static void protocomm_console_task(void *arg)
QueueHandle_t uart_queue; QueueHandle_t uart_queue;
uart_event_t event; 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); uart_driver_install(uart_num, 256, 0, 8, &uart_queue, 0);
/* Initialize the console */ /* Initialize the console */
esp_console_config_t console_config = { 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; pc_console = NULL;
esp_console_deinit(); esp_console_deinit();

View file

@ -26,7 +26,7 @@
static const char *TAG = "protocomm_httpd"; static const char *TAG = "protocomm_httpd";
static protocomm_t *pc_httpd; /* The global protocomm instance for HTTPD */ static protocomm_t *pc_httpd; /* The global protocomm instance for HTTPD */
static bool pc_ext_httpd_handle_provided; static bool pc_ext_httpd_handle_provided = false;
static uint32_t session_id = PROTOCOMM_NO_SESSION_ID; static uint32_t session_id = PROTOCOMM_NO_SESSION_ID;
#define MAX_REQ_BODY_LEN 4096 #define MAX_REQ_BODY_LEN 4096
@ -42,9 +42,9 @@ static esp_err_t common_post_handler(httpd_req_t *req)
int cur_session_id = httpd_req_to_sockfd(req); int cur_session_id = httpd_req_to_sockfd(req);
if (cur_session_id != session_id) { if (cur_session_id != session_id) {
/* Initialise new security session */ /* Initialize new security session */
if (session_id != PROTOCOMM_NO_SESSION_ID) { 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 /* Presently HTTP server doesn't support callback on socket closure so
* previous session can only be closed when new session is requested */ * previous session can only be closed when new session is requested */
if (pc_httpd->sec && pc_httpd->sec->close_transport_session) { if (pc_httpd->sec && pc_httpd->sec->close_transport_session) {
@ -66,7 +66,7 @@ static esp_err_t common_post_handler(httpd_req_t *req)
} }
} }
session_id = cur_session_id; 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) { if (req->content_len <= 0) {
@ -133,7 +133,7 @@ static esp_err_t protocomm_httpd_add_endpoint(const char *ep_name,
return ESP_ERR_INVALID_STATE; 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 */ /* Construct URI name by prepending '/' to ep_name */
char* ep_uri = calloc(1, strlen(ep_name) + 2); char* ep_uri = calloc(1, strlen(ep_name) + 2);
@ -170,7 +170,7 @@ static esp_err_t protocomm_httpd_remove_endpoint(const char *ep_name)
return ESP_ERR_INVALID_STATE; 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 */ /* Construct URI name by prepending '/' to ep_name */
char* ep_uri = calloc(1, strlen(ep_name) + 2); char* ep_uri = calloc(1, strlen(ep_name) + 2);

View file

@ -19,6 +19,7 @@
#include <esp_log.h> #include <esp_log.h>
#include <esp_system.h> #include <esp_system.h>
#include <sys/random.h> #include <sys/random.h>
#include <unistd.h>
#include <unity.h> #include <unity.h>
#include <mbedtls/aes.h> #include <mbedtls/aes.h>
@ -36,7 +37,7 @@
#include "session.pb-c.h" #include "session.pb-c.h"
#ifdef DO_HEAP_TRACING #ifdef CONFIG_HEAP_TRACING
#include <esp_heap_trace.h> #include <esp_heap_trace.h>
#define NUM_RECORDS 100 #define NUM_RECORDS 100
static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM 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; return ESP_FAIL;
} }
#define TEST_VER_STR "<some version string>"
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) static esp_err_t test_req_endpoint(session_t *session)
{ {
uint32_t session_id = session->id; 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_test_data, sizeof(enc_test_data),
&enc_verify_data, &verify_data_len); &enc_verify_data, &verify_data_len);
if (ret != ESP_OK) { if (ret != ESP_OK || !verify_data_len) {
ESP_LOGE(TAG, "test-ep handler failed"); ESP_LOGE(TAG, "test-ep handler failed");
return ESP_FAIL; 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; 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", if (protocomm_add_endpoint(test_pc, "test-ep",
test_req_handler, test_req_handler,
(void *) &test_priv_data) != ESP_OK) { (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) static void stop_test_service(void)
{ {
protocomm_remove_endpoint(test_pc, "test-ep");
protocomm_unset_security(test_pc, "test-sec");
test_sec = NULL; test_sec = NULL;
protocomm_delete(test_pc); protocomm_delete(test_pc);
test_pc = NULL; 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 // Sending request data to echo endpoint encrypted with zero
// public keys on both client and server side should pass // public keys on both client and server side should fail
if (test_req_endpoint(session) != ESP_OK) { if (test_req_endpoint(session) == ESP_OK) {
ESP_LOGE(TAG, "Error testing request endpoint"); ESP_LOGE(TAG, "Error testing request endpoint");
stop_test_service(); stop_test_service();
free(session); free(session);
@ -938,6 +966,13 @@ static esp_err_t test_protocomm (session_t *session)
return ESP_FAIL; 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 // Intialise protocomm session with zero public keys
if (test_new_session(session) != ESP_OK) { if (test_new_session(session) != ESP_OK) {
ESP_LOGE(TAG, "Error creating new session"); ESP_LOGE(TAG, "Error creating new session");
@ -1024,33 +1059,43 @@ static esp_err_t test_security0 (void)
TEST_CASE("leak test", "[PROTOCOMM]") TEST_CASE("leak test", "[PROTOCOMM]")
{ {
#ifdef DO_HEAP_TRACING #ifdef CONFIG_HEAP_TRACING
heap_trace_init_standalone(trace_record, NUM_RECORDS); 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); heap_trace_start(HEAP_TRACE_LEAKS);
#endif #endif
/* Run basic tests for the first time to allow for internal long
* time allocations to happen (not related to protocomm) */
test_security0(); test_security0();
test_security1(); test_security1();
usleep(1000);
#ifdef DO_HEAP_TRACING #ifdef CONFIG_HEAP_TRACING
heap_trace_stop(); heap_trace_stop();
heap_trace_dump(); heap_trace_dump();
#endif #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(); unsigned post_stop_mem = esp_get_free_heap_size();
if (pre_start_mem != post_stop_mem) { 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);
TEST_ASSERT(pre_start_mem != post_stop_mem);
#endif
} }
TEST_CASE("security 0 basic test", "[PROTOCOMM]") TEST_CASE("security 0 basic test", "[PROTOCOMM]")

View file

@ -17,6 +17,10 @@
#include <lwip/inet.h> #include <lwip/inet.h>
#ifdef __cplusplus
extern "C" {
#endif
/** /**
* @brief WiFi STA status for conveying back to the provisioning master * @brief WiFi STA status for conveying back to the provisioning master
*/ */
@ -77,6 +81,15 @@ typedef struct {
uint8_t channel; /*!< Channel of the AP */ uint8_t channel; /*!< Channel of the AP */
} wifi_prov_config_set_data_t; } 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 * @brief Internal handlers for receiving and responding to protocomm
* requests from master * requests from master
@ -89,14 +102,16 @@ typedef struct wifi_prov_config_handlers {
* Handler function called when connection status * Handler function called when connection status
* of the slave (in WiFi station mode) is requested * 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 * Handler function called when WiFi connection configuration
* (eg. AP SSID, password, etc.) of the slave (in WiFi station mode) * (eg. AP SSID, password, etc.) of the slave (in WiFi station mode)
* is to be set to user provided values * 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 * 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 * updated connection status information when `get_status_handler` is
* invoked again by the master. * 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; } 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, 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); uint8_t **outbuf, ssize_t *outlen, void *priv_data);
#ifdef __cplusplus
}
#endif
#endif #endif

View file

@ -72,7 +72,7 @@ static esp_err_t cmd_get_status_handler(WiFiConfigPayload *req,
resp_get_status__init(resp_payload); resp_get_status__init(resp_payload);
wifi_prov_config_get_data_t resp_data; 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) { if (resp_data.wifi_state == WIFI_PROV_STA_CONNECTING) {
resp_payload->sta_state = WIFI_STATION_STATE__Connecting; resp_payload->sta_state = WIFI_STATION_STATE__Connecting;
resp_payload->state_case = RESP_GET_STATUS__STATE_CONNECTED; 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, memcpy(req_data.bssid, req->cmd_set_config->bssid.data,
req->cmd_set_config->bssid.len); req->cmd_set_config->bssid.len);
req_data.channel = req->cmd_set_config->channel; 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; 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); 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; resp_payload->status = STATUS__Success;
} else { } else {
resp_payload->status = STATUS__InvalidArgument; resp_payload->status = STATUS__InvalidArgument;

View file

@ -4,7 +4,9 @@ Wi-Fi Provisioning
Overview 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 * `get_status` - For querying the Wi-Fi connection status
* `set_config` - For setting the Wi-Fi connection credentials * `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 * `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 /* Fill the wifi_prov_config_get_data_t structure
* with Wi-Fi station connection status information. */ * with Wi-Fi station connection status information. */
@ -26,7 +28,7 @@ Application Example
return ESP_OK; 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 /* Copy contents of req_data->ssid and req_data->password
* which are Wi-Fi AP credentials to which the device will connect */ * which are Wi-Fi AP credentials to which the device will connect */
@ -34,7 +36,7 @@ Application Example
return ESP_OK; 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 */ /* Apply the Wi-Fi STA credentials saved during set_config */
@ -47,6 +49,7 @@ Application Example
.get_status_handler = get_status_handler, .get_status_handler = get_status_handler,
.set_config_handler = set_config_handler, .set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler, .apply_config_handler = apply_config_handler,
.ctx = NULL
}; };
/* Set the endpoint handler */ /* Set the endpoint handler */

View file

@ -188,7 +188,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
case SYSTEM_EVENT_STA_GOT_IP: case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "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. */ * Schedule timer to stop provisioning app after 30 seconds. */
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED; g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
if (g_prov && g_prov->timer) { 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; return ESP_ERR_NO_MEM;
} }
/* Initialise app data */ /* Initialize app data */
g_prov->pop = pop; g_prov->pop = pop;
g_prov->security = security; g_prov->security = security;

View file

@ -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.) 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 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)); memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) { 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; 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, wifi_prov_ctx_t **ctx)
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
{ {
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) { if (wifi_cfg) {
free(wifi_cfg); free_config(ctx);
wifi_cfg = NULL;
} }
wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t)); wifi_cfg = new_config(ctx);
if (!wifi_cfg) { if (!wifi_cfg) {
ESP_LOGE(TAG, "Unable to alloc wifi config"); ESP_LOGE(TAG, "Unable to alloc wifi config");
return ESP_FAIL; 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; 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) { if (!wifi_cfg) {
ESP_LOGE(TAG, "WiFi config not set"); ESP_LOGE(TAG, "WiFi config not set");
return ESP_FAIL; return ESP_FAIL;
@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void)
app_prov_configure_sta(wifi_cfg); app_prov_configure_sta(wifi_cfg);
ESP_LOGI(TAG, "WiFi Credentials Applied"); ESP_LOGI(TAG, "WiFi Credentials Applied");
free(wifi_cfg); free_config(ctx);
wifi_cfg = NULL;
return ESP_OK; return ESP_OK;
} }
@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler, .get_status_handler = get_status_handler,
.set_config_handler = set_config_handler, .set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler, .apply_config_handler = apply_config_handler,
.ctx = NULL
}; };

View file

@ -101,8 +101,8 @@ static void app_prov_stop_service(void)
protocomm_delete(g_prov->pc); protocomm_delete(g_prov->pc);
} }
/* Callback to be invoked by timer */ /* Task spawned by timer callback */
static void _stop_prov_cb(void * arg) static void stop_prov_task(void * arg)
{ {
ESP_LOGI(TAG, "Stopping provisioning"); ESP_LOGI(TAG, "Stopping provisioning");
app_prov_stop_service(); app_prov_stop_service();
@ -116,6 +116,14 @@ static void _stop_prov_cb(void * arg)
free(g_prov); free(g_prov);
g_prov = NULL; g_prov = NULL;
ESP_LOGI(TAG, "Provisioning stopped"); 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. /* 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: case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "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. */ * Schedule timer to stop provisioning app after 30 seconds. */
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED; g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
if (g_prov && g_prov->timer) { 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; return ESP_ERR_NO_MEM;
} }
/* Initialise app data */ /* Initialize app data */
g_prov->pop = pop; g_prov->pop = pop;
g_prov->security = security; 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, .callback = _stop_prov_cb,
.arg = NULL, .arg = NULL,
.dispatch_method = ESP_TIMER_TASK, .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); esp_err_t err = esp_timer_create(&timer_conf, &g_prov->timer);
if (err != ESP_OK) { if (err != ESP_OK) {

View file

@ -23,9 +23,32 @@
static const char* TAG = "app_prov_handler"; 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)); memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) { 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; 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, wifi_prov_ctx_t **ctx)
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
{ {
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) { if (wifi_cfg) {
free(wifi_cfg); free_config(ctx);
wifi_cfg = NULL;
} }
wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t)); wifi_cfg = new_config(ctx);
if (!wifi_cfg) { if (!wifi_cfg) {
ESP_LOGE(TAG, "Unable to alloc wifi config"); ESP_LOGE(TAG, "Unable to alloc wifi config");
return ESP_FAIL; 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; 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) { if (!wifi_cfg) {
ESP_LOGE(TAG, "WiFi config not set"); ESP_LOGE(TAG, "WiFi config not set");
return ESP_FAIL; return ESP_FAIL;
@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void)
app_prov_configure_sta(wifi_cfg); app_prov_configure_sta(wifi_cfg);
ESP_LOGI(TAG, "WiFi Credentials Applied"); ESP_LOGI(TAG, "WiFi Credentials Applied");
free(wifi_cfg); free_config(ctx);
wifi_cfg = NULL;
return ESP_OK; return ESP_OK;
} }
@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler, .get_status_handler = get_status_handler,
.set_config_handler = set_config_handler, .set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler, .apply_config_handler = apply_config_handler,
.ctx = NULL
}; };

View file

@ -116,8 +116,8 @@ static void app_prov_stop_service(void)
protocomm_delete(g_prov->pc); protocomm_delete(g_prov->pc);
} }
/* Callback to be invoked by timer */ /* Task spawned by timer callback */
static void _stop_softap_cb(void * arg) static void stop_prov_task(void * arg)
{ {
ESP_LOGI(TAG, "Stopping provisioning"); ESP_LOGI(TAG, "Stopping provisioning");
app_prov_stop_service(); app_prov_stop_service();
@ -132,6 +132,14 @@ static void _stop_softap_cb(void * arg)
free(g_prov); free(g_prov);
g_prov = NULL; g_prov = NULL;
ESP_LOGI(TAG, "Provisioning stopped"); 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. /* Event handler for starting/stopping provisioning.
@ -162,7 +170,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
case SYSTEM_EVENT_STA_GOT_IP: case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "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. */ * Schedule timer to stop provisioning app after 30 seconds. */
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED; g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
if (g_prov && g_prov->timer) { if (g_prov && g_prov->timer) {
@ -174,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. * to reconnect and get STA connection status from the device.
* Otherwise, the AP will be turned off before the user can * Otherwise, the AP will be turned off before the user can
* reconnect and thus the user app will see connection timed out, * 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); esp_timer_start_once(g_prov->timer, 30000*1000U);
} }
break; break;
@ -303,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) 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(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t err = esp_wifi_init(&cfg); esp_err_t err = esp_wifi_init(&cfg);
if (err != ESP_OK) { if (err != ESP_OK) {
@ -372,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 */ /* Create timer object as a member of app data */
esp_timer_create_args_t timer_conf = { esp_timer_create_args_t timer_conf = {
.callback = _stop_softap_cb, .callback = _stop_prov_cb,
.arg = NULL, .arg = NULL,
.dispatch_method = ESP_TIMER_TASK, .dispatch_method = ESP_TIMER_TASK,
.name = "stop_softap_tm" .name = "stop_softap_tm"

View file

@ -24,6 +24,29 @@
static const char* TAG = "app_prov_handler"; 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 *******************/ /****************** Handler for Custom Configuration *******************/
static esp_err_t custom_config_handler(const custom_config_t *config) 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; custom_prov_config_handler_t custom_prov_handler = custom_config_handler;
/****************** Handlers for Wi-Fi Configuration *******************/ /****************** 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)); memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) { 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; 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, wifi_prov_ctx_t **ctx)
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
{ {
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) { if (wifi_cfg) {
free(wifi_cfg); free_config(ctx);
wifi_cfg = NULL;
} }
wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t)); wifi_cfg = new_config(ctx);
if (!wifi_cfg) { if (!wifi_cfg) {
ESP_LOGE(TAG, "Unable to alloc wifi config"); ESP_LOGE(TAG, "Unable to alloc wifi config");
return ESP_FAIL; 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; 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) { if (!wifi_cfg) {
ESP_LOGE(TAG, "WiFi config not set"); ESP_LOGE(TAG, "WiFi config not set");
return ESP_FAIL; return ESP_FAIL;
@ -106,8 +128,7 @@ static esp_err_t apply_config_handler(void)
app_prov_configure_sta(wifi_cfg); app_prov_configure_sta(wifi_cfg);
ESP_LOGI(TAG, "WiFi Credentials Applied"); ESP_LOGI(TAG, "WiFi Credentials Applied");
free(wifi_cfg); free_config(ctx);
wifi_cfg = NULL;
return ESP_OK; return ESP_OK;
} }
@ -115,4 +136,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler, .get_status_handler = get_status_handler,
.set_config_handler = set_config_handler, .set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler, .apply_config_handler = apply_config_handler,
.ctx = NULL
}; };

View file

@ -102,8 +102,8 @@ static void app_prov_stop_service(void)
protocomm_delete(g_prov->pc); protocomm_delete(g_prov->pc);
} }
/* Callback to be invoked by timer */ /* Task spawned by timer callback */
static void _stop_softap_cb(void * arg) static void stop_prov_task(void * arg)
{ {
ESP_LOGI(TAG, "Stopping provisioning"); ESP_LOGI(TAG, "Stopping provisioning");
app_prov_stop_service(); app_prov_stop_service();
@ -118,6 +118,14 @@ static void _stop_softap_cb(void * arg)
free(g_prov); free(g_prov);
g_prov = NULL; g_prov = NULL;
ESP_LOGI(TAG, "Provisioning stopped"); 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. /* Event handler for starting/stopping provisioning.
@ -148,7 +156,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
case SYSTEM_EVENT_STA_GOT_IP: case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "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. */ * Schedule timer to stop provisioning app after 30 seconds. */
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED; g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
if (g_prov && g_prov->timer) { if (g_prov && g_prov->timer) {
@ -160,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. * to reconnect and get STA connection status from the device.
* Otherwise, the AP will be turned off before the user can * Otherwise, the AP will be turned off before the user can
* reconnect and thus the user app will see connection timed out, * 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); esp_timer_start_once(g_prov->timer, 30000*1000U);
} }
break; break;
@ -290,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) 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(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t err = esp_wifi_init(&cfg); esp_err_t err = esp_wifi_init(&cfg);
if (err != ESP_OK) { if (err != ESP_OK) {
@ -353,13 +361,13 @@ esp_err_t app_prov_start_softap_provisioning(const char *ssid, const char *pass,
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
/* Initialise app data */ /* Initialize app data */
g_prov->pop = pop; g_prov->pop = pop;
g_prov->security = security; g_prov->security = security;
/* Create timer object as a member of app data */ /* Create timer object as a member of app data */
esp_timer_create_args_t timer_conf = { esp_timer_create_args_t timer_conf = {
.callback = _stop_softap_cb, .callback = _stop_prov_cb,
.arg = NULL, .arg = NULL,
.dispatch_method = ESP_TIMER_TASK, .dispatch_method = ESP_TIMER_TASK,
.name = "stop_softap_tm" .name = "stop_softap_tm"

View file

@ -23,9 +23,32 @@
static const char* TAG = "app_prov_handler"; 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)); memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) { 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; 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, wifi_prov_ctx_t **ctx)
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
{ {
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) { if (wifi_cfg) {
free(wifi_cfg); free_config(ctx);
wifi_cfg = NULL;
} }
wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t)); wifi_cfg = new_config(ctx);
if (!wifi_cfg) { if (!wifi_cfg) {
ESP_LOGE(TAG, "Unable to alloc wifi config"); ESP_LOGE(TAG, "Unable to alloc wifi config");
return ESP_FAIL; 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; 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) { if (!wifi_cfg) {
ESP_LOGE(TAG, "WiFi config not set"); ESP_LOGE(TAG, "WiFi config not set");
return ESP_FAIL; return ESP_FAIL;
@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void)
app_prov_configure_sta(wifi_cfg); app_prov_configure_sta(wifi_cfg);
ESP_LOGI(TAG, "WiFi Credentials Applied"); ESP_LOGI(TAG, "WiFi Credentials Applied");
free(wifi_cfg); free_config(ctx);
wifi_cfg = NULL;
return ESP_OK; return ESP_OK;
} }
@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler, .get_status_handler = get_status_handler,
.set_config_handler = set_config_handler, .set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler, .apply_config_handler = apply_config_handler,
.ctx = NULL
}; };

View file

@ -77,7 +77,7 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None):
def version_match(tp, protover): def version_match(tp, protover):
try: try:
response = tp.send_data('proto-ver', protover) response = tp.send_data('proto-ver', protover)
if response != "SUCCESS": if response != protover:
return False return False
return True return True
except RuntimeError as e: except RuntimeError as e: