esp32: multi ap slots plus PEM certs and parallel build fixes

This commit is contained in:
Andy Green 2017-05-11 15:02:01 +08:00
parent a7def3ce44
commit 54236bd437
9 changed files with 231 additions and 42 deletions

View file

@ -1118,7 +1118,8 @@ if (GENCERTS)
COMMAND "${OPENSSL_EXECUTABLE}"
req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
RESULT_VARIABLE OPENSSL_RETURN_CODE
OUTPUT_QUIET ERROR_QUIET)
# OUTPUT_QUIET ERROR_QUIET
)
if (OPENSSL_RETURN_CODE)
message(WARNING "!!! Failed to generate SSL certificate for Test Server!!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")

View file

@ -11,6 +11,8 @@ CROSS_PATH:= $(shell dirname $(CROSS_PATH1) )/..
# -DOPENSSL_INCLUDE_DIRS="${PWD}/../../boringssl/include" \
# -DNDEBUG=1 after cflags
# -DOPENSSL_LIBRARIES=x \
# -DCOMPONENT_PATH=$(COMPONENT_PATH) \
.PHONY: build
build:
@ -19,12 +21,10 @@ build:
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS) -DNDEBUG=1" \
-DIDF_PATH=$(IDF_PATH) \
-DCROSS_PATH=$(CROSS_PATH) \
-DCOMPONENT_PATH=$(COMPONENT_PATH) \
-DBUILD_DIR_BASE=$(BUILD_DIR_BASE) \
-DCMAKE_TOOLCHAIN_FILE=$(COMPONENT_PATH)/cross-esp32.cmake \
-DCMAKE_BUILD_TYPE=RELEASE \
-DOPENSSL_INCLUDE_DIR=${IDF_PATH}/components/openssl/include \
-DOPENSSL_LIBRARIES=x \
-DLWS_WITH_STATS=1 \
-DZLIB_LIBRARY=$(BUILD_DIR_BASE)/zlib/libzlib.a \
-DZLIB_INCLUDE_DIR=$(COMPONENT_PATH)/../zlib \

View file

@ -565,6 +565,9 @@ struct lws_esp32 {
char serial[16];
char opts[16];
char model[16];
char group[16];
char role[16];
char active_ssid[32];
char access_pw[16];
mdns_server_t *mdns;
char region;

View file

@ -584,8 +584,52 @@ struct lws_esp32 lws_esp32 = {
.region = WIFI_COUNTRY_US, // default to safest option
};
/*
* Group AP / Station State
*/
enum lws_gapss {
LWS_GAPSS_INITIAL, /* just started up, init and move to LWS_GAPSS_SCAN */
LWS_GAPSS_SCAN, /*
* Unconnected, scanning: AP known in one of the config
* slots -> configure it, start timeout + LWS_GAPSS_STAT,
* if no AP already up in same group with lower MAC,
* after a random period start up our AP (LWS_GAPSS_AP)
*/
LWS_GAPSS_AP, /*
* Trying to be the group AP... periodically do a scan
* LWS_GAPSS_AP_SCAN, faster and then slower
*/
LWS_GAPSS_AP_SCAN, /*
* doing a scan while trying to be the group AP... if
* we see a lower MAC being the AP for the same group
* AP, abandon being an AP and join that AP as a
* station
*/
LWS_GAPSS_STAT_GRP_AP, /*
* We have decided to join another group member who is
* being the AP, as its MAC is lower than ours. This
* is a stable state, but we still do periodic scans
* (LWS_GAPSS_STAT_GRP_AP_SCAN) and will always prefer
* an AP configured in a slot.
*/
LWS_GAPSS_STAT_GRP_AP_SCAN,
/*
* We have joined a group member who is doing the AP
* job... we want to check every now and then if a
* configured AP has appeared that we should better
* use instead. Otherwise stay in LWS_GAPSS_STAT_GRP_AP
*/
LWS_GAPSS_STAT, /*
* trying to connect to another non-group AP. If we
* don't get an IP within a timeout and retries,
* blacklist it and go back
*/
};
static romfs_t lws_esp32_romfs;
static TimerHandle_t leds_timer;
//static enum lws_gapss gapss = LWS_GAPSS_INITIAL;
struct esp32_file {
const struct inode *i;
@ -599,9 +643,9 @@ uint32_t lws_esp32_get_reboot_type(void)
int n = 0;
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
if (nvs_get_blob(nvh, "ssl-pub.der", NULL, &s) == ESP_OK)
if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
n = 1;
if (nvs_get_blob(nvh, "ssl-pri.der", NULL, &s) == ESP_OK)
if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
n |= 2;
nvs_close(nvh);
@ -642,9 +686,14 @@ esp_err_t lws_esp32_event_passthru(void *ctx, system_event_t *event)
break;
case SYSTEM_EVENT_STA_GOT_IP:
lws_esp32.inet = 1;
render_ip(lws_esp32.sta_ip, sizeof(lws_esp32.sta_ip) - 1, (uint8_t *)&event->event_info.got_ip.ip_info.ip);
render_ip(lws_esp32.sta_mask, sizeof(lws_esp32.sta_mask) - 1, (uint8_t *)&event->event_info.got_ip.ip_info.netmask);
render_ip(lws_esp32.sta_gw, sizeof(lws_esp32.sta_gw) - 1, (uint8_t *)&event->event_info.got_ip.ip_info.gw);
render_ip(lws_esp32.sta_ip, sizeof(lws_esp32.sta_ip) - 1,
(uint8_t *)&event->event_info.got_ip.ip_info.ip);
render_ip(lws_esp32.sta_mask, sizeof(lws_esp32.sta_mask) - 1,
(uint8_t *)&event->event_info.got_ip.ip_info.netmask);
render_ip(lws_esp32.sta_gw, sizeof(lws_esp32.sta_gw) - 1,
(uint8_t *)&event->event_info.got_ip.ip_info.gw);
break;
case SYSTEM_EVENT_SCAN_DONE:
break;
default:
break;
@ -770,10 +819,15 @@ lws_esp32_wlan_nvs_get(int retry)
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
s = sizeof(config.sta.ssid) - 1;
if (nvs_get_str(nvh, "ssid", (char *)sta_config.sta.ssid, &s) != ESP_OK)
if (nvs_get_str(nvh, "ssid0", (char *)sta_config.sta.ssid, &s) != ESP_OK)
lws_esp32_force_ap = 1;
/* set the ssid we last tried to connect to */
strncpy(lws_esp32.active_ssid, (char *)sta_config.sta.ssid, sizeof(lws_esp32.active_ssid) - 1);
lws_esp32.active_ssid[sizeof(lws_esp32.active_ssid) - 1] = '\0';
s = sizeof(config.sta.password) - 1;
if (nvs_get_str(nvh, "password", (char *)sta_config.sta.password, &s) != ESP_OK)
if (nvs_get_str(nvh, "password0", (char *)sta_config.sta.password, &s) != ESP_OK)
lws_esp32_force_ap = 1;
s = sizeof(lws_esp32.serial) - 1;
if (nvs_get_str(nvh, "serial", lws_esp32.serial, &s) != ESP_OK)
@ -793,6 +847,14 @@ lws_esp32_wlan_nvs_get(int retry)
lws_esp32.access_pw[0] = '\0';
nvs_get_str(nvh, "access_pw", lws_esp32.access_pw, &s);
lws_esp32.group[0] = '\0';
s = sizeof(lws_esp32.group);
nvs_get_str(nvh, "group", lws_esp32.group, &s);
lws_esp32.role[0] = '\0';
s = sizeof(lws_esp32.role);
nvs_get_str(nvh, "role", lws_esp32.role, &s);
nvs_close(nvh);
if (retry && sta_config.sta.ssid[0]) {
@ -957,8 +1019,8 @@ lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
info->options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info->ssl_cert_filepath = "ssl-pub.der";
info->ssl_private_key_filepath = "ssl-pri.der";
info->ssl_cert_filepath = "ssl-pub.pem";
info->ssl_private_key_filepath = "ssl-pri.pem";
}
int
@ -1024,10 +1086,10 @@ lws_esp32_init(struct lws_context_creation_info *info)
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
n = 0;
s = 1;
if (nvs_get_blob(nvh, "ssl-pub.der", NULL, &s) == ESP_OK)
if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
n = 1;
s = 1;
if (nvs_get_blob(nvh, "ssl-pri.der", NULL, &s) == ESP_OK)
if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
n |= 2;
nvs_close(nvh);

View file

@ -2078,6 +2078,9 @@ LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len);
LWS_EXTERN int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
lws_filepos_t *amount);
LWS_EXTERN int alloc_pem_to_der_file(struct lws_context *context, const char *filename, uint8_t **buf,
lws_filepos_t *amount);
LWS_EXTERN void
lws_same_vh_protocol_remove(struct lws *wsi);
LWS_EXTERN void

View file

@ -365,7 +365,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
lws_filepos_t flen;
int err;
if (alloc_file(vhost->context, info->ssl_cert_filepath, &p,
if (alloc_pem_to_der_file(vhost->context, info->ssl_cert_filepath, &p,
&flen)) {
lwsl_err("couldn't find cert file %s\n",
info->ssl_cert_filepath);
@ -378,7 +378,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
return 1;
}
if (alloc_file(vhost->context,
if (alloc_pem_to_der_file(vhost->context,
info->ssl_private_key_filepath, &p, &flen)) {
lwsl_err("couldn't find cert file %s\n",
info->ssl_cert_filepath);

View file

@ -72,8 +72,11 @@ int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
n = 2;
goto bail;
}
if (nvs_get_blob(nvh, filename, (char *)*buf, &s) != ESP_OK)
if (nvs_get_blob(nvh, filename, (char *)*buf, &s) != ESP_OK) {
free(*buf);
n = 1;
goto bail;
}
*amount = s;
@ -82,6 +85,60 @@ bail:
return n;
}
int alloc_pem_to_der_file(struct lws_context *context, const char *filename, uint8_t **buf,
lws_filepos_t *amount)
{
uint8_t *pem, *p, *q, *end;
lws_filepos_t len;
int n;
n = alloc_file(context, filename, &pem, &len);
if (n)
return n;
/* trim the first line */
p = pem;
end = p + len;
if (strncmp((char *)p, "-----", 5))
goto bail;
p += 5;
while (p < end && *p != '\n' && *p != '-')
p++;
if (*p != '-')
goto bail;
while (p < end && *p != '\n')
p++;
if (p >= end)
goto bail;
p++;
/* trim the last line */
q = end - 2;
while (q > pem && *q != '\n')
q--;
if (*q != '\n')
goto bail;
*q = '\0';
*amount = lws_b64_decode_string((char *)p, (char *)pem, len);
*buf = pem;
return 0;
bail:
free(pem);
return 4;
}
#endif
int openssl_websocket_private_data_index,
@ -336,7 +393,7 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
if (n < 0) {
n = lws_ssl_get_error(wsi, n);
lwsl_notice("get_ssl_err result %d\n", n);
// lwsl_notice("get_ssl_err result %d\n", n);
if (n == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) {
lwsl_debug("%s: WANT_READ\n", __func__);
lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);

View file

@ -27,6 +27,7 @@ typedef enum {
SCAN_STATE_NONE,
SCAN_STATE_INITIAL,
SCAN_STATE_INITIAL_MANIFEST,
SCAN_STATE_KNOWN,
SCAN_STATE_LIST,
SCAN_STATE_FINAL
} scan_state;
@ -84,9 +85,17 @@ struct per_vhost_data__esplws_scan {
};
static const struct store_json store_json[] = {
{ "ssid\":\"", "ssid" },
{ ",\"pw\":\"", "password" },
{ "\"ssid0\":\"", "ssid0" },
{ ",\"pw0\":\"", "password0" },
{ "\"ssid1\":\"", "ssid1" },
{ ",\"pw1\":\"", "password1" },
{ "\"ssid2\":\"", "ssid2" },
{ ",\"pw2\":\"", "password2" },
{ "\"ssid3\":\"", "ssid3" },
{ ",\"pw3\":\"", "password3" },
{ ",\"access_pw\":\"", "access_pw" },
{ "{\"group\":\"", "group" },
{ "{\"role\":\"", "role" },
{ ",\"region\":\"", "region" },
};
@ -240,7 +249,7 @@ scan_finished(void *v)
esp_wifi_connect();
}
static const char *ssl_names[] = { "ssl-pub.der", "ssl-pri.der" };
static const char *ssl_names[] = { "ssl-pub.pem", "ssl-pri.pem" };
static int
file_upload_cb(void *data, const char *name, const char *filename,
@ -363,10 +372,9 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
switch (pss->scan_state) {
struct timeval t;
char ssid[32];
uint8_t mac[6];
struct lws_esp32_image i;
char img_factory[512], img_ota[512];
char img_factory[512], img_ota[512], group[16];
int grt;
case SCAN_STATE_INITIAL:
@ -379,13 +387,13 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
n = 0;
if (nvs_get_blob(nvh, "ssl-pub.der", NULL, &s) == ESP_OK)
if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
n = 1;
if (nvs_get_blob(nvh, "ssl-pri.der", NULL, &s) == ESP_OK)
if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
n |= 2;
s = sizeof(ssid) - 1;
ssid[0] = '\0';
nvs_get_str(nvh, "ssid", ssid, &s);
s = sizeof(group) - 1;
group[0] = '\0';
nvs_get_str(nvh, "group", group, &s);
nvs_close(nvh);
@ -422,6 +430,7 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
" \"conn_ip\":\"%s\",\n"
" \"conn_mask\":\"%s\",\n"
" \"conn_gw\":\"%s\",\n"
" \"group\":\"%s\",\n"
" \"img_factory\": %s,\n"
" \"img_ota\": %s,\n",
lws_esp32.model,
@ -432,10 +441,11 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
lws_esp32.region,
n & 1, (n >> 1) & 1,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] | 1,
ssid,
lws_esp32.active_ssid,
lws_esp32.sta_ip,
lws_esp32.sta_mask,
lws_esp32.sta_gw,
group,
img_factory,
img_ota
);
@ -455,7 +465,46 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
);
p += snprintf((char *)p, end - p,
" \"aps\":[\n");
" \"known\":[\n");
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
pss->scan_state = SCAN_STATE_KNOWN;
break;
case SCAN_STATE_KNOWN:
if (nvs_open("lws-station", NVS_READONLY, &nvh)) {
lwsl_notice("unable to open nvh\n");
return -1;
}
for (m = 0; m < 4; m++) {
char name[10], ssid[32];
unsigned int pp = 0, use = 0;
if (m)
*p++ = ',';
s = sizeof(ssid) - 1;
ssid[0] = '\0';
lws_snprintf(name, sizeof(name) - 1, "ssid%d", m);
nvs_get_str(nvh, name, ssid, &s);
lws_snprintf(name, sizeof(name) - 1, "password%d", m);
s = 10;
nvs_get_str(nvh, name, NULL, &s);
pp = !!s;
lws_snprintf(name, sizeof(name) - 1, "use%d", m);
nvs_get_u32(nvh, name, &use);
p += snprintf((char *)p, end - p,
"{\"ssid\":\"%s\",\n"
" \"pp\":\"%u\",\n"
"\"use\":\"%u\"}\n",
ssid, pp, use);
}
nvs_close(nvh);
p += snprintf((char *)p, end - p,
"], \"aps\":[\n");
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
pss->scan_state = SCAN_STATE_LIST;
@ -534,7 +583,7 @@ issue:
if (vhd->json_len && strstr((const char *)in, "update-ota"))
goto auton;
if (strstr((const char *)in, "reset"))
if (strstr((const char *)in, "\"reset\""))
goto sched_reset;
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
@ -547,10 +596,18 @@ issue:
continue;
/* only change access password if he has physical access to device */
if (n == 2 && lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
if (n == 8 && lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
continue;
lwsl_notice("%s '%s\n", store_json[n].nvs, p);
if (n == 9) {
strncpy(lws_esp32.group, p, sizeof(lws_esp32.group) - 1);
lws_esp32.group[sizeof(lws_esp32.group) - 1] = '\0';
}
if (n == 10) {
strncpy(lws_esp32.role, p, sizeof(lws_esp32.role) - 1);
lws_esp32.role[sizeof(lws_esp32.role) - 1] = '\0';
}
if (nvs_set_str(nvh, store_json[n].nvs, p) != ESP_OK) {
lwsl_err("Unable to store %s in nvm\n", store_json[n].nvs);
@ -561,17 +618,21 @@ issue:
nvs_commit(nvh);
nvs_close(nvh);
if (lws_esp32_get_reboot_type() == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
if (strstr((const char *)in, "\"factory-reset\"")) {
if (lws_esp32_get_reboot_type() ==
LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
if (strstr((const char *)in, "factory-reset")) {
lwsl_notice("Doing factory reset\n");
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
nvs_erase_all(nvh);
n = nvs_erase_all(nvh);
if (n)
lwsl_notice("erase_all failed %d\n", n);
nvs_commit(nvh);
nvs_close(nvh);
goto sched_reset;
}
} else
lwsl_notice("failed on factory button boot\n");
}
if (vhd->scan_ongoing)

View file

@ -15,13 +15,12 @@ ifeq ($(FAC),)
FAC=0
endif
export FAC
DIRNAME:=$(shell basename $$(pwd) | tr -d '\n')
.PHONY: romfs.img
pack.img:
$(COMPONENT_PATH)/../build/pack.img: $(APP_BIN)
GNUSTAT=stat ;\
if [ `which gstat 2>/dev/null` ] ; then GNUSTAT=gstat ; fi ;\
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
cp $(COMPONENT_PATH)/../build/$(PROJECT_NAME).bin $(COMPONENT_PATH)/../build/$$DIRNAME.bin ; \
genromfs -f $(COMPONENT_PATH)/../build/romfs.img -d $(COMPONENT_PATH)/../romfs-files ; \
RLEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/romfs.img) ;\
LEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/$$DIRNAME.bin) ;\
@ -54,6 +53,7 @@ pack.img:
printf %02x $$(( ( $$JLEN / 65536 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
printf %02x $$(( ( $$JLEN / 16777216 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
cat $(jbi) >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
cp $(COMPONENT_PATH)/../build/$$DIRNAME.bin $(COMPONENT_PATH)/../build/pack.img ;\
LEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/$$DIRNAME.bin) ;\
cp $(COMPONENT_PATH)/../build/$$DIRNAME.bin $(COMPONENT_PATH)/../build/$$DIRNAME-$$UNIXTIME.bin ;\
printf " After ROMFS + Build info: 0x%06x (%8d)\n" $$LEN $$LEN
@ -74,9 +74,11 @@ endif
cat $(F)/build/json-buildinfo >> build/manifest.json
echo -n -e "\r\n}\r\n" >> build/manifest.json
all: pack.img
all: $(COMPONENT_PATH)/../build/pack.img
flash_ota:
flash: $(COMPONENT_PATH)/../build/pack.img
flash_ota: $(COMPONENT_PATH)/../build/pack.img
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \
--chip esp32 \