From: Andy Green Date: Thu, 11 May 2017 07:02:01 +0000 (+0800) Subject: esp32: multi ap slots plus PEM certs and parallel build fixes X-Git-Tag: accepted/tizen/4.0/unified/20171012.191640~115 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=54236bd437a71ddb85151756d1fb09cb0090533f;p=platform%2Fupstream%2Flibwebsockets.git esp32: multi ap slots plus PEM certs and parallel build fixes --- diff --git a/CMakeLists.txt b/CMakeLists.txt index b035f8d..4f1fd54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}") diff --git a/component.mk b/component.mk index ed334a8..340bd8a 100644 --- a/component.mk +++ b/component.mk @@ -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 \ diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 4065aad..679dddc 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -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; diff --git a/lib/lws-plat-esp32.c b/lib/lws-plat-esp32.c index dc54911..8294fef 100644 --- a/lib/lws-plat-esp32.c +++ b/lib/lws-plat-esp32.c @@ -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); diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 21fccdc..e2cee95 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -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 diff --git a/lib/ssl-server.c b/lib/ssl-server.c index 039c7bf..873ad04 100644 --- a/lib/ssl-server.c +++ b/lib/ssl-server.c @@ -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); diff --git a/lib/ssl.c b/lib/ssl.c index b5f9e1e..ea1f4af 100644 --- a/lib/ssl.c +++ b/lib/ssl.c @@ -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); diff --git a/plugins/protocol_esp32_lws_scan.c b/plugins/protocol_esp32_lws_scan.c index b6b2963..1a8c9f4 100644 --- a/plugins/protocol_esp32_lws_scan.c +++ b/plugins/protocol_esp32_lws_scan.c @@ -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) diff --git a/scripts/esp32.mk b/scripts/esp32.mk index 0049fe6..95d03f8 100644 --- a/scripts/esp32.mk +++ b/scripts/esp32.mk @@ -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 \