Fix nasty case of memory corruption by enduser_setup.

Turns out that running wifi_station_config() from a network callback can
be a Really Really Bad Idea(tm).
This commit is contained in:
Johny Mattsson 2016-03-01 17:54:10 +11:00
parent 41022c3b6a
commit 04889813f3
1 changed files with 37 additions and 18 deletions

View File

@ -43,6 +43,7 @@
#include "user_interface.h"
#include "espconn.h"
#include "flash_fs.h"
#include "task/task.h"
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define LITLEN(strliteral) (sizeof (strliteral) -1)
@ -244,6 +245,7 @@ typedef struct
static enduser_setup_state_t *state;
static bool manual = false;
static task_handle_t do_station_cfg_handle;
static int enduser_setup_start(lua_State* L);
static int enduser_setup_stop(lua_State* L);
@ -492,6 +494,32 @@ static void enduser_setup_http_urldecode(char *dst, const char *src, int src_len
}
/**
* Task to do the actual station configuration.
* This config *cannot* be done in the network receive callback or serious
* issues like memory corruption occur.
*/
static void do_station_cfg (task_param_t param, uint8_t prio)
{
struct station_config *cnf = (struct station_config *)param;
(void)prio;
/* Best-effort disconnect-reconfig-reconnect. If the device is currently
* connected, the disconnect will work but the connect will report failure
* (though it will actually start connecting). If the devices is not
* connected, the disconnect may fail but the connect will succeed. A
* solid head-in-the-sand approach seems to be the best tradeoff on
* functionality-vs-code-size.
* TODO: maybe use an error callback to at least report if the set config
* call fails.
*/
wifi_station_disconnect ();
wifi_station_set_config (cnf);
wifi_station_connect ();
os_free (cnf);
}
/**
* Handle HTTP Credentials
*
@ -522,30 +550,18 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data
return 1;
}
struct station_config cnf;
c_memset(&cnf, 0, sizeof(struct station_config));
enduser_setup_http_urldecode(cnf.ssid, name_str_start, name_str_len);
enduser_setup_http_urldecode(cnf.password, pwd_str_start, pwd_str_len);
struct station_config *cnf = os_zalloc(sizeof(struct station_config));
enduser_setup_http_urldecode(cnf->ssid, name_str_start, name_str_len);
enduser_setup_http_urldecode(cnf->password, pwd_str_start, pwd_str_len);
if (!wifi_station_disconnect())
{
ENDUSER_SETUP_ERROR("station_start failed. wifi_station_disconnect failed.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
}
if (!wifi_station_set_config(&cnf))
{
ENDUSER_SETUP_ERROR("station_start failed. wifi_station_set_config failed.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_FATAL);
}
if (wifi_station_connect())
{
ENDUSER_SETUP_ERROR("station_start failed. wifi_station_connect failed.\n", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_FATAL);
}
task_post_medium(do_station_cfg_handle, (task_param_t)cnf);
ENDUSER_SETUP_DEBUG(lua_getstate(), "WiFi Credentials Stored");
ENDUSER_SETUP_DEBUG(lua_getstate(), "-----------------------");
ENDUSER_SETUP_DEBUG(lua_getstate(), "name: ");
ENDUSER_SETUP_DEBUG(lua_getstate(), cnf.ssid);
ENDUSER_SETUP_DEBUG(lua_getstate(), cnf->ssid);
ENDUSER_SETUP_DEBUG(lua_getstate(), "pass: ");
ENDUSER_SETUP_DEBUG(lua_getstate(), cnf.password);
ENDUSER_SETUP_DEBUG(lua_getstate(), cnf->password);
ENDUSER_SETUP_DEBUG(lua_getstate(), "-----------------------");
return 0;
@ -1248,6 +1264,9 @@ static int enduser_setup_start(lua_State *L)
{
ENDUSER_SETUP_DEBUG(L, "enduser_setup_start");
if (!do_station_cfg_handle)
do_station_cfg_handle = task_get_id(do_station_cfg);
if(enduser_setup_init(L))
goto failed;