From 2be968c78d15ccdc4aa5ddbabb841a74b58569db Mon Sep 17 00:00:00 2001 From: Paul Letnyanko Date: Sun, 7 Apr 2024 18:05:59 +0300 Subject: [PATCH 1/2] Added ability to specify WPA2 PSK in place of WiFi password This is a feature that's already supported by ESP devices. However, in case of Tuya devices (at least for BK7231N) it's invaluable as it can reduce the connect time by 4 seconds or more. It's all because in order to start negotiation, each client is required to derive the PSK that is a function of SSID and Password. And it's a deterministic function: it can be calculated once, stored somewhere and used many times for the same pair of SSID and Password. Actually, looking at BDK it's obvious that native firmware does exactly that. It even has a caching system that from looks of it is capable of storing multiple records. Saving and restoring connection parameters is a more complex feature that is not implemented by this PR. However, it can now be easily done with the fixes made in `bk_wlan_start_sta_adv_fix`. This PR allows user to manually pre-calculate PSK for each of hist networks and use them instead of plain passwords in YAML. Which already works with ESP32/ESP8266, but raises `Passphrase too long` error in LibreTiny: all due to BDK limitations that are now circumvented. On my cb3s based door sensor, using `fast_connect: true` with pre-calculated PSK I have managed to achieve a boot-to-mqtt-and-sleep time that is faster than the original firmware (probably because of higher latency): around 1.25-1.40s. Using a fixed BSSID and channel can push it down 1s or less. Additionally, this PR removes the need for two supplemental config structs in WiFiClass, STA_CFG and STA_ADV_CFG, in favor of the latter. More info on PSK can be found here: https://jorisvr.nl/wpapsk.html --- .../arduino/libraries/WiFi/WiFi.cpp | 1 - .../arduino/libraries/WiFi/WiFiGeneric.cpp | 2 +- .../arduino/libraries/WiFi/WiFiPrivate.h | 2 - .../arduino/libraries/WiFi/WiFiSTA.cpp | 78 ++++----- cores/beken-72xx/base/fixups/wlan_ui.c | 150 ++++++++++++++++++ cores/beken-72xx/base/sdk_extern.h | 1 + .../arduino/libraries/api/WiFi/WiFi.cpp | 2 +- 7 files changed, 183 insertions(+), 53 deletions(-) create mode 100644 cores/beken-72xx/base/fixups/wlan_ui.c diff --git a/cores/beken-72xx/arduino/libraries/WiFi/WiFi.cpp b/cores/beken-72xx/arduino/libraries/WiFi/WiFi.cpp index 32f7d2e15..928170d55 100644 --- a/cores/beken-72xx/arduino/libraries/WiFi/WiFi.cpp +++ b/cores/beken-72xx/arduino/libraries/WiFi/WiFi.cpp @@ -6,7 +6,6 @@ WiFiClass::WiFiClass() { data = (WiFiData *)calloc(1, sizeof(WiFiData)); DATA->scanSem = xSemaphoreCreateBinary(); - STA_CFG.dhcp_mode = DHCP_CLIENT; STA_ADV_CFG.dhcp_mode = DHCP_CLIENT; } diff --git a/cores/beken-72xx/arduino/libraries/WiFi/WiFiGeneric.cpp b/cores/beken-72xx/arduino/libraries/WiFi/WiFiGeneric.cpp index 1374c76d3..e3953f62f 100644 --- a/cores/beken-72xx/arduino/libraries/WiFi/WiFiGeneric.cpp +++ b/cores/beken-72xx/arduino/libraries/WiFi/WiFiGeneric.cpp @@ -71,7 +71,7 @@ WiFiMode WiFiClass::getMode() { WiFiStatus WiFiClass::status() { rw_evt_type status = DATA->lastStaEvent; - if (status == RW_EVT_STA_CONNECTED && STA_CFG.dhcp_mode == DHCP_DISABLE) + if (status == RW_EVT_STA_CONNECTED && STA_ADV_CFG.dhcp_mode == DHCP_DISABLE) status = RW_EVT_STA_GOT_IP; return eventTypeToStatus(status); } diff --git a/cores/beken-72xx/arduino/libraries/WiFi/WiFiPrivate.h b/cores/beken-72xx/arduino/libraries/WiFi/WiFiPrivate.h index 38ec80c00..f82ac7c9a 100644 --- a/cores/beken-72xx/arduino/libraries/WiFi/WiFiPrivate.h +++ b/cores/beken-72xx/arduino/libraries/WiFi/WiFiPrivate.h @@ -56,7 +56,6 @@ extern void wifiEventHandler(rw_evt_type event); #define IP_FMT "%u.%u.%u.%u" typedef struct { - network_InitTypeDef_st configSta; network_InitTypeDef_adv_st configStaAdv; network_InitTypeDef_ap_st configAp; unsigned long scannedAt; @@ -73,7 +72,6 @@ typedef struct { #define pDATA ((WiFiData *)pWiFi->data) #define cDATA ((WiFiData *)cls->data) -#define STA_CFG (DATA->configSta) #define STA_ADV_CFG (DATA->configStaAdv) #define AP_CFG (DATA->configAp) #define IP_STATUS (DATA->statusIp) diff --git a/cores/beken-72xx/arduino/libraries/WiFi/WiFiSTA.cpp b/cores/beken-72xx/arduino/libraries/WiFi/WiFiSTA.cpp index a5558d101..3f0628c4c 100644 --- a/cores/beken-72xx/arduino/libraries/WiFi/WiFiSTA.cpp +++ b/cores/beken-72xx/arduino/libraries/WiFi/WiFiSTA.cpp @@ -13,27 +13,16 @@ WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, cons disconnect(false); - if (bssid) { - strcpy(STA_ADV_CFG.ap_info.ssid, ssid); - if (passphrase) { - strcpy(STA_ADV_CFG.key, passphrase); - STA_ADV_CFG.key_len = strlen(passphrase); - } else { - STA_ADV_CFG.key[0] = '\0'; - STA_ADV_CFG.key_len = 0; - } - STA_ADV_CFG.ap_info.channel = channel; - STA_ADV_CFG.wifi_retry_interval = 100; + strcpy(STA_ADV_CFG.ap_info.ssid, ssid); + if (passphrase) { + STA_ADV_CFG.key_len = strlen(passphrase); + memcpy(STA_ADV_CFG.key, passphrase, STA_ADV_CFG.key_len); } else { - strcpy(STA_CFG.wifi_ssid, ssid); - if (passphrase) { - strcpy(STA_CFG.wifi_key, passphrase); - } else { - STA_CFG.wifi_key[0] = '\0'; - } - STA_CFG.wifi_retry_interval = 100; - STA_CFG.wifi_mode = BK_STATION; + STA_ADV_CFG.key[0] = '\0'; + STA_ADV_CFG.key_len = 0; } + STA_ADV_CFG.ap_info.channel = channel; + STA_ADV_CFG.wifi_retry_interval = 100; if (reconnect(bssid)) return WL_CONNECTED; @@ -42,27 +31,17 @@ WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, cons } bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) { - STA_CFG.dhcp_mode = localIP ? DHCP_DISABLE : DHCP_CLIENT; STA_ADV_CFG.dhcp_mode = localIP ? DHCP_DISABLE : DHCP_CLIENT; if (localIP) { - sprintf(STA_CFG.local_ip_addr, IP_FMT, localIP[0], localIP[1], localIP[2], localIP[3]); - sprintf(STA_CFG.net_mask, IP_FMT, subnet[0], subnet[1], subnet[2], subnet[3]); - sprintf(STA_CFG.gateway_ip_addr, IP_FMT, gateway[0], gateway[1], gateway[2], gateway[3]); sprintf(STA_ADV_CFG.local_ip_addr, IP_FMT, localIP[0], localIP[1], localIP[2], localIP[3]); sprintf(STA_ADV_CFG.net_mask, IP_FMT, subnet[0], subnet[1], subnet[2], subnet[3]); sprintf(STA_ADV_CFG.gateway_ip_addr, IP_FMT, gateway[0], gateway[1], gateway[2], gateway[3]); if (dns1) { - sprintf(STA_CFG.dns_server_ip_addr, IP_FMT, dns1[0], dns1[1], dns1[2], dns1[3]); sprintf(STA_ADV_CFG.dns_server_ip_addr, IP_FMT, dns1[0], dns1[1], dns1[2], dns1[3]); } else { - STA_CFG.dns_server_ip_addr[0] = '\0'; STA_ADV_CFG.dns_server_ip_addr[0] = '\0'; } } else { - STA_CFG.local_ip_addr[0] = '\0'; - STA_CFG.net_mask[0] = '\0'; - STA_CFG.gateway_ip_addr[0] = '\0'; - STA_CFG.dns_server_ip_addr[0] = '\0'; STA_ADV_CFG.local_ip_addr[0] = '\0'; STA_ADV_CFG.net_mask[0] = '\0'; STA_ADV_CFG.gateway_ip_addr[0] = '\0'; @@ -74,11 +53,11 @@ bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, I sta_ip_down(); ip_address_set( BK_STATION, - STA_CFG.dhcp_mode, - STA_CFG.local_ip_addr, - STA_CFG.net_mask, - STA_CFG.gateway_ip_addr, - STA_CFG.dns_server_ip_addr + STA_ADV_CFG.dhcp_mode, + STA_ADV_CFG.local_ip_addr, + STA_ADV_CFG.net_mask, + STA_ADV_CFG.gateway_ip_addr, + STA_ADV_CFG.dns_server_ip_addr ); sta_ip_start(); } @@ -86,7 +65,7 @@ bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, I } bool WiFiClass::reconnect(const uint8_t *bssid) { - if (!bssid && !STA_CFG.wifi_ssid[0]) { + if (!bssid && !STA_ADV_CFG.ap_info.ssid[0]) { LT_EM(WIFI, "(B)SSID not specified"); goto error; } @@ -94,19 +73,26 @@ bool WiFiClass::reconnect(const uint8_t *bssid) { if (bssid) { LT_IM(WIFI, "Connecting to " MACSTR, MAC2STR(bssid)); } else { - LT_IM(WIFI, "Connecting to %s", STA_CFG.wifi_ssid); + LT_IM(WIFI, "Connecting to %s", STA_ADV_CFG.ap_info.ssid); } - LT_DM(WIFI, "Data = %p", DATA->configSta); + LT_DM(WIFI, "Data = %p", DATA->configStaAdv); - if (bssid) + if (bssid) { memcpy(STA_ADV_CFG.ap_info.bssid, bssid, 6); - else - memset(STA_CFG.wifi_bssid, 0x00, 6); + } else { + memset(STA_ADV_CFG.ap_info.bssid, 0x00, 6); + } - if (STA_CFG.dhcp_mode == DHCP_DISABLE) { - LT_DM(WIFI, "Static IP: %s / %s / %s", STA_CFG.local_ip_addr, STA_CFG.net_mask, STA_CFG.gateway_ip_addr); - LT_DM(WIFI, "Static DNS: %s", STA_CFG.dns_server_ip_addr); + if (STA_ADV_CFG.dhcp_mode == DHCP_DISABLE) { + LT_DM( + WIFI, + "Static IP: %s / %s / %s", + STA_ADV_CFG.local_ip_addr, + STA_ADV_CFG.net_mask, + STA_ADV_CFG.gateway_ip_addr + ); + LT_DM(WIFI, "Static DNS: %s", STA_ADV_CFG.dns_server_ip_addr); } else { LT_DM(WIFI, "Using DHCP"); } @@ -114,11 +100,7 @@ bool WiFiClass::reconnect(const uint8_t *bssid) { LT_DM(WIFI, "Starting WiFi..."); __wrap_bk_printf_disable(); - if (bssid) { - bk_wlan_start_sta_adv(&STA_ADV_CFG); - } else { - bk_wlan_start_sta(&STA_CFG); - } + bk_wlan_start_sta_adv_fix(&STA_ADV_CFG); __wrap_bk_printf_enable(); LT_DM(WIFI, "Start OK"); diff --git a/cores/beken-72xx/base/fixups/wlan_ui.c b/cores/beken-72xx/base/fixups/wlan_ui.c new file mode 100644 index 000000000..77ad2be78 --- /dev/null +++ b/cores/beken-72xx/base/fixups/wlan_ui.c @@ -0,0 +1,150 @@ +#include "include.h" +#include "wlan_ui_pub.h" +#include "rw_pub.h" +#include "param_config.h" +#include "wpa_psk_cache.h" + +extern void bk_wlan_sta_init_adv(network_InitTypeDef_adv_st *inNetworkInitParaAdv); + +extern void bk_wlan_sta_adv_param_2_sta(network_InitTypeDef_adv_st *sta_adv,network_InitTypeDef_st* sta); + +OSStatus bk_wlan_start_sta_adv_fix(network_InitTypeDef_adv_st *inNetworkInitParaAdv) +{ + if (bk_wlan_is_monitor_mode()) { + os_printf("airkiss is not finish yet, stop airkiss or waiting it finish!\r\n"); + return 0; + } + +#if !CFG_WPA_CTRL_IFACE +#if CFG_ROLE_LAUNCH + rl_status_set_private_state(RL_PRIV_STATUS_STA_ADV_RDY); +#endif +#if CFG_ROLE_LAUNCH + rl_status_set_st_state(RL_ST_STATUS_RESTART_ST); +#endif + + bk_wlan_stop(BK_STATION); +#if CFG_ROLE_LAUNCH + if (rl_pre_sta_set_status(RL_STATUS_STA_INITING)) + return -1; + + rl_status_reset_st_state(RL_ST_STATUS_RESTART_HOLD | RL_ST_STATUS_RESTART_ST); + rl_status_set_private_state(RL_PRIV_STATUS_STA_ADV); + rl_status_reset_private_state(RL_PRIV_STATUS_STA_ADV_RDY); + LAUNCH_REQ lreq; + + lreq.req_type = LAUNCH_REQ_STA; + bk_wlan_sta_adv_param_2_sta(inNetworkInitParaAdv, &lreq.descr); + + rl_sta_adv_register_cache_station(&lreq); +#endif + + bk_wlan_sta_init_adv(inNetworkInitParaAdv); + + /* + * Key buffer is not guaranteed to be null terminated: there is a separate + * `key_len` field that stores the length. We have to copy the data to a + * temporary stack buffer. Fortunately, `wpa_psk_request()` does not keep + * the reference, as it's not needed: the end result is PSK that is either + * derived from the `ssid` + `key` or is already available. `key` is just a + * transient argument. + */ + { + char key_buffer[PMK_LEN + 1]; + + /* Make copy with a guaranteed null terminator. */ + os_memcpy(key_buffer, g_sta_param_ptr->key, g_sta_param_ptr->key_len); + key_buffer[g_sta_param_ptr->key_len + 1] = '\0'; + + /* + * let wpa_psk_cal thread to caculate psk. + * XXX: If you know psk value, fill last two parameters of `wpa_psk_request()'. + */ + wpa_psk_request(g_sta_param_ptr->ssid.array, g_sta_param_ptr->ssid.length, + key_buffer, NULL, 0); + } + + supplicant_main_entry(inNetworkInitParaAdv->ap_info.ssid); + + net_wlan_add_netif(&g_sta_param_ptr->own_mac); + + +#else /* CFG_WPA_CTRL_IFACE */ + wlan_sta_config_t config; + +#if (CFG_SOC_NAME == SOC_BK7231N) + if (get_ate_mode_state()) { + // cunliang20210407 set blk_standby_cfg with blk_txen_cfg like txevm, qunshan confirmed + rwnx_cal_en_extra_txpa(); + } +#endif + bk_wlan_sta_init_adv(inNetworkInitParaAdv); + + /* + * Key buffer is not guaranteed to be null terminated: there is a separate + * `key_len` field that stores the length. We have to copy the data to a + * temporary stack buffer. Fortunately, `wpa_psk_request()` does not keep + * the reference, as it's not needed: the end result is PSK that is either + * derived from the `ssid` + `key` or is already available. `key` is just a + * transient argument. + */ + { + char key_buffer[PMK_LEN + 1]; + + /* Make copy with a guaranteed null terminator. */ + os_memcpy(key_buffer, g_sta_param_ptr->key, g_sta_param_ptr->key_len); + key_buffer[g_sta_param_ptr->key_len + 1] = '\0'; + + /* + * let wpa_psk_cal thread to caculate psk. + * XXX: If you know psk value, fill last two parameters of `wpa_psk_request()'. + */ + wpa_psk_request(g_sta_param_ptr->ssid.array, g_sta_param_ptr->ssid.length, + key_buffer, NULL, 0); + } + + /* disconnect previous connected network */ + wlan_sta_disconnect(); + + /* start wpa_supplicant */ + wlan_sta_enable(); + + /* set network parameters: ssid, passphase */ + wlan_sta_set((uint8_t*)inNetworkInitParaAdv->ap_info.ssid, os_strlen(inNetworkInitParaAdv->ap_info.ssid), + (uint8_t*)inNetworkInitParaAdv->key); + + /* set fast connect bssid */ + os_memset(&config, 0, sizeof(config)); + /* + * This API has no way to communicate whether BSSID was supplied or not. + * So we will use an assumption that no valid endpoint will ever use the + * `00:00:00:00:00:00`. It's basically a MAC address and no valid device + * should ever use the value consisting of all zeroes. + * + * We have just zeroed out the `config` struct so we can use those zeroes + * for comparison with our input argument. + */ + if (os_memcmp(config.u.bssid, inNetworkInitParaAdv->ap_info.bssid, ETH_ALEN)) { + os_memcpy(config.u.bssid, inNetworkInitParaAdv->ap_info.bssid, ETH_ALEN); + config.field = WLAN_STA_FIELD_BSSID; + wpa_ctrl_request(WPA_CTRL_CMD_STA_SET, &config); + } + + /* set fast connect freq */ + os_memset(&config, 0, sizeof(config)); + config.u.channel = inNetworkInitParaAdv->ap_info.channel; + config.field = WLAN_STA_FIELD_FREQ; + wpa_ctrl_request(WPA_CTRL_CMD_STA_SET, &config); + + /* connect to AP */ + wlan_sta_connect(g_sta_param_ptr->fast_connect_set ? g_sta_param_ptr->fast_connect.chann : 0); + +#endif + ip_address_set(BK_STATION, inNetworkInitParaAdv->dhcp_mode, + inNetworkInitParaAdv->local_ip_addr, + inNetworkInitParaAdv->net_mask, + inNetworkInitParaAdv->gateway_ip_addr, + inNetworkInitParaAdv->dns_server_ip_addr); + + return 0; +} diff --git a/cores/beken-72xx/base/sdk_extern.h b/cores/beken-72xx/base/sdk_extern.h index 4cbccb07b..4ddb6d3cb 100644 --- a/cores/beken-72xx/base/sdk_extern.h +++ b/cores/beken-72xx/base/sdk_extern.h @@ -20,6 +20,7 @@ void uart_hw_set_change(uint8_t uport, bk_uart_config_t *uart_config); int uart_rx_callback_set(int uport, uart_callback callback, void *param); void sctrl_enter_rtos_deep_sleep(PS_DEEP_CTRL_PARAM *deep_param); void ps_delay(volatile UINT16 times); +OSStatus bk_wlan_start_sta_adv_fix(network_InitTypeDef_adv_st *inNetworkInitParaAdv); #ifdef __cplusplus } // extern "C" diff --git a/cores/common/arduino/libraries/api/WiFi/WiFi.cpp b/cores/common/arduino/libraries/api/WiFi/WiFi.cpp index d20012a9e..281635d5a 100644 --- a/cores/common/arduino/libraries/api/WiFi/WiFi.cpp +++ b/cores/common/arduino/libraries/api/WiFi/WiFi.cpp @@ -61,7 +61,7 @@ bool WiFiClass::validate(const char *ssid, const char *passphrase) { LT_WM(WIFI, "Passphrase too short (%u)", length); return false; } - if (length > 63) { + if (length > 64) { LT_WM(WIFI, "Passphrase too long (%u)", length); return false; } From f042c322ed72247564d397eaf3ebc65aed6c5a6b Mon Sep 17 00:00:00 2001 From: Paul Letnyanko Date: Sun, 7 Apr 2024 22:16:18 +0300 Subject: [PATCH 2/2] Fix of a pathetic off-by-one bug, plus cleanup. --- cores/beken-72xx/base/fixups/wlan_ui.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/cores/beken-72xx/base/fixups/wlan_ui.c b/cores/beken-72xx/base/fixups/wlan_ui.c index 77ad2be78..f0922ca72 100644 --- a/cores/beken-72xx/base/fixups/wlan_ui.c +++ b/cores/beken-72xx/base/fixups/wlan_ui.c @@ -11,7 +11,6 @@ extern void bk_wlan_sta_adv_param_2_sta(network_InitTypeDef_adv_st *sta_adv,netw OSStatus bk_wlan_start_sta_adv_fix(network_InitTypeDef_adv_st *inNetworkInitParaAdv) { if (bk_wlan_is_monitor_mode()) { - os_printf("airkiss is not finish yet, stop airkiss or waiting it finish!\r\n"); return 0; } @@ -53,8 +52,8 @@ OSStatus bk_wlan_start_sta_adv_fix(network_InitTypeDef_adv_st *inNetworkInitPara char key_buffer[PMK_LEN + 1]; /* Make copy with a guaranteed null terminator. */ - os_memcpy(key_buffer, g_sta_param_ptr->key, g_sta_param_ptr->key_len); - key_buffer[g_sta_param_ptr->key_len + 1] = '\0'; + memcpy(key_buffer, g_sta_param_ptr->key, g_sta_param_ptr->key_len); + key_buffer[g_sta_param_ptr->key_len] = '\0'; /* * let wpa_psk_cal thread to caculate psk. @@ -92,8 +91,8 @@ OSStatus bk_wlan_start_sta_adv_fix(network_InitTypeDef_adv_st *inNetworkInitPara char key_buffer[PMK_LEN + 1]; /* Make copy with a guaranteed null terminator. */ - os_memcpy(key_buffer, g_sta_param_ptr->key, g_sta_param_ptr->key_len); - key_buffer[g_sta_param_ptr->key_len + 1] = '\0'; + memcpy(key_buffer, g_sta_param_ptr->key, g_sta_param_ptr->key_len); + key_buffer[g_sta_param_ptr->key_len] = '\0'; /* * let wpa_psk_cal thread to caculate psk. @@ -110,11 +109,11 @@ OSStatus bk_wlan_start_sta_adv_fix(network_InitTypeDef_adv_st *inNetworkInitPara wlan_sta_enable(); /* set network parameters: ssid, passphase */ - wlan_sta_set((uint8_t*)inNetworkInitParaAdv->ap_info.ssid, os_strlen(inNetworkInitParaAdv->ap_info.ssid), + wlan_sta_set((uint8_t*)inNetworkInitParaAdv->ap_info.ssid, strlen(inNetworkInitParaAdv->ap_info.ssid), (uint8_t*)inNetworkInitParaAdv->key); /* set fast connect bssid */ - os_memset(&config, 0, sizeof(config)); + memset(&config, 0, sizeof(config)); /* * This API has no way to communicate whether BSSID was supplied or not. * So we will use an assumption that no valid endpoint will ever use the @@ -124,14 +123,14 @@ OSStatus bk_wlan_start_sta_adv_fix(network_InitTypeDef_adv_st *inNetworkInitPara * We have just zeroed out the `config` struct so we can use those zeroes * for comparison with our input argument. */ - if (os_memcmp(config.u.bssid, inNetworkInitParaAdv->ap_info.bssid, ETH_ALEN)) { - os_memcpy(config.u.bssid, inNetworkInitParaAdv->ap_info.bssid, ETH_ALEN); + if (memcmp(config.u.bssid, inNetworkInitParaAdv->ap_info.bssid, ETH_ALEN)) { + memcpy(config.u.bssid, inNetworkInitParaAdv->ap_info.bssid, ETH_ALEN); config.field = WLAN_STA_FIELD_BSSID; wpa_ctrl_request(WPA_CTRL_CMD_STA_SET, &config); } /* set fast connect freq */ - os_memset(&config, 0, sizeof(config)); + memset(&config, 0, sizeof(config)); config.u.channel = inNetworkInitParaAdv->ap_info.channel; config.field = WLAN_STA_FIELD_FREQ; wpa_ctrl_request(WPA_CTRL_CMD_STA_SET, &config);