Skip to content

Commit f2a1500

Browse files
committed
Merge branch 'task/prov_improvements' into 'master'
app_wifi: Minor feature additions to provisioning workflow See merge request app-frameworks/esp-rainmaker!294
2 parents 174a38b + e1dacc2 commit f2a1500

File tree

12 files changed

+450
-78
lines changed

12 files changed

+450
-78
lines changed

CHANGES.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changes
22

3+
## 25-Jan-2022 (app_wifi: Minor feature additions to provisioning workflow)
4+
5+
Added a 30 minute timeout for Wi-Fi provisioning as a security measure. A device reboot will be
6+
required to restart provisioning after it times out. The value can changed using the
7+
`CONFIG_APP_WIFI_PROV_TIMEOUT_PERIOD` config option. A value of 0 will disable the timeout logic.
8+
`APP_WIFI_EVENT_PROV_TIMEOUT` event will be triggerd to indicate that the provisioning has timed out.
9+
310
## 25-Jan-2022 (examples: Enable some security features and change order of component dirs)
411

512
A couple of security features were added some time back, viz.

components/esp_rainmaker/include/esp_rmaker_user_mapping.h

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ typedef enum {
2525
ESP_RMAKER_USER_MAPPING_RESET = 0,
2626
/** Mapping has started */
2727
ESP_RMAKER_USER_MAPPING_STARTED,
28+
/** Mapping request sent to cloud */
29+
ESP_RMAKER_USER_MAPPING_REQ_SENT,
2830
/** Mapping is done */
2931
ESP_RMAKER_USER_MAPPING_DONE,
3032
} esp_rmaker_user_mapping_state_t;

components/esp_rainmaker/src/core/esp_rmaker_internal.h

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ esp_err_t esp_rmaker_handle_set_params(char *data, size_t data_len, esp_rmaker_r
107107
esp_err_t esp_rmaker_user_mapping_prov_init(void);
108108
esp_err_t esp_rmaker_user_mapping_prov_deinit(void);
109109
esp_err_t esp_rmaker_user_node_mapping_init(void);
110+
esp_err_t esp_rmaker_user_node_mapping_deinit(void);
110111
esp_err_t esp_rmaker_reset_user_node_mapping(void);
111112
esp_err_t esp_rmaker_init_local_ctrl_service(void);
112113
esp_err_t esp_rmaker_start_local_ctrl_service(const char *serv_name);

components/esp_rainmaker/src/core/esp_rmaker_user_mapping.c

+65-11
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <esp_log.h>
1717
#include <esp_event.h>
1818
#include <nvs.h>
19+
#include <freertos/FreeRTOS.h>
20+
#include <freertos/semphr.h>
1921
#include <wifi_provisioning/manager.h>
2022
#include <json_generator.h>
2123
#include <esp_rmaker_work_queue.h>
@@ -35,14 +37,21 @@ static const char *TAG = "esp_rmaker_user_mapping";
3537
#define USER_RESET_ID "esp-rmaker"
3638
#define USER_RESET_KEY "failed"
3739

40+
/* A delay large enough to allow the tasks to get the semaphore, but small
41+
* enough to prevent tasks getting blocked for long.
42+
*/
43+
#define SEMAPHORE_DELAY_MSEC 5000
44+
3845
typedef struct {
3946
char *user_id;
4047
char *secret_key;
4148
int mqtt_msg_id;
49+
bool sent;
4250
} esp_rmaker_user_mapping_data_t;
4351

4452
static esp_rmaker_user_mapping_data_t *rmaker_user_mapping_data;
4553
esp_rmaker_user_mapping_state_t rmaker_user_mapping_state;
54+
SemaphoreHandle_t esp_rmaker_user_mapping_lock = NULL;
4655

4756
static void esp_rmaker_user_mapping_cleanup_data(void)
4857
{
@@ -82,10 +91,13 @@ static void esp_rmaker_user_mapping_event_handler(void* arg, esp_event_base_t ev
8291
* has indeed reached the RainMaker cloud.
8392
*/
8493
int msg_id = *((int *)event_data);
85-
if (msg_id == rmaker_user_mapping_data->mqtt_msg_id) {
94+
if (xSemaphoreTake(esp_rmaker_user_mapping_lock, SEMAPHORE_DELAY_MSEC/portTICK_PERIOD_MS) != pdTRUE) {
95+
ESP_LOGE(TAG, "Failed to take semaphore.");
96+
return;
97+
}
98+
if ((rmaker_user_mapping_data != NULL) && (msg_id == rmaker_user_mapping_data->mqtt_msg_id)) {
8699
ESP_LOGI(TAG, "User Node association message published successfully.");
87-
esp_rmaker_user_mapping_data_t *data = (esp_rmaker_user_mapping_data_t *)arg;
88-
if (data && (strcmp(data->user_id, USER_RESET_ID) == 0)) {
100+
if (strcmp(rmaker_user_mapping_data->user_id, USER_RESET_ID) == 0) {
89101
rmaker_user_mapping_state = ESP_RMAKER_USER_MAPPING_RESET;
90102
esp_rmaker_post_event(RMAKER_EVENT_USER_NODE_MAPPING_RESET, NULL, 0);
91103
} else {
@@ -106,36 +118,47 @@ static void esp_rmaker_user_mapping_event_handler(void* arg, esp_event_base_t ev
106118
esp_event_handler_unregister(RMAKER_COMMON_EVENT, RMAKER_MQTT_EVENT_PUBLISHED,
107119
&esp_rmaker_user_mapping_event_handler);
108120
}
121+
xSemaphoreGive(esp_rmaker_user_mapping_lock);
109122
}
110123
}
111124

112125
static void esp_rmaker_user_mapping_cb(void *priv_data)
113126
{
114-
esp_rmaker_user_mapping_data_t *data = (esp_rmaker_user_mapping_data_t *)priv_data;
115-
if (!data) {
127+
if (xSemaphoreTake(esp_rmaker_user_mapping_lock, SEMAPHORE_DELAY_MSEC/portTICK_PERIOD_MS) != pdTRUE) {
128+
ESP_LOGE(TAG, "Failed to take semaphore.");
129+
return;
130+
}
131+
/* If there is no user node mapping data, or if the data is already sent, just return */
132+
if (rmaker_user_mapping_data == NULL || rmaker_user_mapping_data->sent == true) {
133+
xSemaphoreGive(esp_rmaker_user_mapping_lock);
116134
return;
117135
}
118136
esp_event_handler_register(RMAKER_COMMON_EVENT, RMAKER_MQTT_EVENT_PUBLISHED,
119-
&esp_rmaker_user_mapping_event_handler, data);
137+
&esp_rmaker_user_mapping_event_handler, NULL);
120138
char publish_payload[200];
121139
json_gen_str_t jstr;
122140
json_gen_str_start(&jstr, publish_payload, sizeof(publish_payload), NULL, NULL);
123141
json_gen_start_object(&jstr);
124142
char *node_id = esp_rmaker_get_node_id();
125143
json_gen_obj_set_string(&jstr, "node_id", node_id);
126-
json_gen_obj_set_string(&jstr, "user_id", data->user_id);
127-
json_gen_obj_set_string(&jstr, "secret_key", data->secret_key);
144+
json_gen_obj_set_string(&jstr, "user_id", rmaker_user_mapping_data->user_id);
145+
json_gen_obj_set_string(&jstr, "secret_key", rmaker_user_mapping_data->secret_key);
128146
if (esp_rmaker_user_node_mapping_get_state() != ESP_RMAKER_USER_MAPPING_DONE) {
129147
json_gen_obj_set_bool(&jstr, "reset", true);
130148
}
131149
json_gen_end_object(&jstr);
132150
json_gen_str_end(&jstr);
133151
char publish_topic[100];
134152
snprintf(publish_topic, sizeof(publish_topic), "node/%s/%s", node_id, USER_MAPPING_TOPIC_SUFFIX);
135-
esp_err_t err = esp_rmaker_mqtt_publish(publish_topic, publish_payload, strlen(publish_payload), RMAKER_MQTT_QOS1, &data->mqtt_msg_id);
153+
esp_err_t err = esp_rmaker_mqtt_publish(publish_topic, publish_payload, strlen(publish_payload), RMAKER_MQTT_QOS1, &rmaker_user_mapping_data->mqtt_msg_id);
154+
ESP_LOGI(TAG, "MQTT Publish: %s", publish_payload);
136155
if (err != ESP_OK) {
137156
ESP_LOGE(TAG, "MQTT Publish Error %d", err);
157+
} else {
158+
rmaker_user_mapping_state = ESP_RMAKER_USER_MAPPING_REQ_SENT;
159+
rmaker_user_mapping_data->sent = true;
138160
}
161+
xSemaphoreGive(esp_rmaker_user_mapping_lock);
139162
return;
140163
}
141164

@@ -175,20 +198,32 @@ static bool esp_rmaker_user_mapping_detect_reset(const char *user_id)
175198

176199
esp_err_t esp_rmaker_start_user_node_mapping(char *user_id, char *secret_key)
177200
{
201+
if (esp_rmaker_user_mapping_lock == NULL) {
202+
ESP_LOGE(TAG, "User Node mapping not initialised.");
203+
return ESP_FAIL;
204+
}
205+
if (xSemaphoreTake(esp_rmaker_user_mapping_lock, SEMAPHORE_DELAY_MSEC/portTICK_PERIOD_MS) != pdTRUE) {
206+
ESP_LOGE(TAG, "Failed to take semaphore.");
207+
return ESP_FAIL;
208+
}
178209
if (rmaker_user_mapping_data) {
179210
esp_rmaker_user_mapping_cleanup_data();
180211
}
181212

182213
rmaker_user_mapping_data = calloc(1, sizeof(esp_rmaker_user_mapping_data_t));
183214
if (!rmaker_user_mapping_data) {
184-
return ESP_FAIL;
215+
ESP_LOGE(TAG, "Failed to allocate memory for rmaker_user_mapping_data.");
216+
xSemaphoreGive(esp_rmaker_user_mapping_lock);
217+
return ESP_ERR_NO_MEM;
185218
}
186219
rmaker_user_mapping_data->user_id = strdup(user_id);
187220
if (!rmaker_user_mapping_data->user_id) {
221+
ESP_LOGE(TAG, "Failed to allocate memory for user_id.");
188222
goto user_mapping_error;
189223
}
190224
rmaker_user_mapping_data->secret_key = strdup(secret_key);
191225
if (!rmaker_user_mapping_data->secret_key) {
226+
ESP_LOGE(TAG, "Failed to allocate memory for secret_key.");
192227
goto user_mapping_error;
193228
}
194229
if (esp_rmaker_user_mapping_detect_reset(user_id)) {
@@ -197,14 +232,17 @@ esp_err_t esp_rmaker_start_user_node_mapping(char *user_id, char *secret_key)
197232
} else {
198233
rmaker_user_mapping_state = ESP_RMAKER_USER_MAPPING_DONE;
199234
}
200-
if (esp_rmaker_work_queue_add_task(esp_rmaker_user_mapping_cb, rmaker_user_mapping_data) != ESP_OK) {
235+
if (esp_rmaker_work_queue_add_task(esp_rmaker_user_mapping_cb, NULL) != ESP_OK) {
236+
ESP_LOGE(TAG, "Failed to queue user mapping task.");
201237
goto user_mapping_error;
202238
}
203239
esp_rmaker_user_mapping_prov_deinit();
240+
xSemaphoreGive(esp_rmaker_user_mapping_lock);
204241
return ESP_OK;
205242

206243
user_mapping_error:
207244
esp_rmaker_user_mapping_cleanup_data();
245+
xSemaphoreGive(esp_rmaker_user_mapping_lock);
208246
return ESP_FAIL;
209247
}
210248

@@ -311,5 +349,21 @@ esp_err_t esp_rmaker_user_node_mapping_init(void)
311349
#else
312350
rmaker_user_mapping_state = ESP_RMAKER_USER_MAPPING_DONE;
313351
#endif
352+
if (!esp_rmaker_user_mapping_lock) {
353+
esp_rmaker_user_mapping_lock = xSemaphoreCreateMutex();
354+
if (!esp_rmaker_user_mapping_lock) {
355+
ESP_LOGE(TAG, "Failed to create Mutex");
356+
return ESP_FAIL;
357+
}
358+
}
359+
return ESP_OK;
360+
}
361+
362+
esp_err_t esp_rmaker_user_node_mapping_deinit(void)
363+
{
364+
if (esp_rmaker_user_mapping_lock) {
365+
vSemaphoreDelete(esp_rmaker_user_mapping_lock);
366+
esp_rmaker_user_mapping_lock = NULL;
367+
}
314368
return ESP_OK;
315369
}

examples/common/app_wifi/Kconfig.projbuild

+32
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,42 @@ menu "ESP RainMaker App Wi-Fi Provisioning"
2525
default 1 if APP_WIFI_PROV_TRANSPORT_SOFTAP
2626
default 2 if APP_WIFI_PROV_TRANSPORT_BLE
2727

28+
config APP_WIFI_RESET_PROV_ON_FAILURE
29+
bool
30+
default y
31+
prompt "Reset provisioned credentials and state machine after session failure"
32+
help
33+
Enable reseting provisioned credentials and state machine after session failure.
34+
This will restart the provisioning service after retries are exhausted.
35+
36+
config APP_WIFI_PROV_MAX_RETRY_CNT
37+
int
38+
default 5
39+
prompt "Max retries before reseting provisioning state machine"
40+
depends on APP_WIFI_RESET_PROV_ON_FAILURE
41+
help
42+
Set the Maximum retry to avoid reconnecting to an inexistent AP or if credentials
43+
are misconfigured. Provisioned credentials are erased and internal state machine
44+
is reset after this threshold is reached.
45+
2846
config APP_WIFI_SHOW_DEMO_INTRO_TEXT
2947
bool "Show intro text for demos"
3048
default n
3149
help
3250
Show some intro text for demos in order to help users understand more about ESP RainMaker.
3351

52+
config APP_WIFI_PROV_TIMEOUT_PERIOD
53+
int "Provisioning Timeout"
54+
default 30
55+
help
56+
Timeout (in minutes) after which the provisioning will auto stop. A reboot will be required
57+
to restart provisioning. It is always recommended to set this to some non zero value, especially
58+
if you are not using PoP. Set to 0 if you do not want provisioning to auto stop.
59+
60+
config APP_WIFI_PROV_NAME_PREFIX
61+
string "Provisioning Name Prefix"
62+
default "PROV"
63+
help
64+
Provisioning Name Prefix.
65+
3466
endmenu

0 commit comments

Comments
 (0)