Files
squeezelite-esp32/components/wifi-manager/network_wifi.c
2023-12-04 23:25:57 -05:00

961 lines
36 KiB
C

#ifdef NETWORK_WIFI_LOG_LEVEL
#define LOG_LOCAL_LEVEL NETWORK_WIFI_LOG_LEVEL
#endif
#include "network_wifi.h"
#include "cJSON.h"
#include "dns_server.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "lwip/sockets.h"
#include "messaging.h"
#include "network_status.h"
#include <string.h>
#pragma message("fixme: search for TODO in the code below")
#include "platform_esp32.h"
#include "tools.h"
#include "trace.h"
#include "accessors.h"
static void network_wifi_event_handler(
void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
static char* get_disconnect_code_desc(uint8_t reason);
esp_err_t network_wifi_get_blob(void* target, size_t size, const char* key);
static inline const char* ssid_string(const wifi_sta_config_t* sta);
static inline const char* password_string(const wifi_sta_config_t* sta);
static const char* status_file_name = "status.bin";
#define MAX_CREDENTIALS sizeof(platform->net.credentials) / sizeof(sys_WifiSTAEntry)
static const char TAG[] = "network_wifi";
esp_netif_t* wifi_netif;
esp_netif_t* wifi_ap_netif;
extern sys_Status status;
#define UINT_TO_STRING(val) \
static char loc[sizeof(val) + 1]; \
memset(loc, 0x00, sizeof(loc)); \
strlcpy(loc, (char*)val, sizeof(loc)); \
return loc;
static inline const char* ssid_string(const wifi_sta_config_t* sta) { UINT_TO_STRING(sta->ssid); }
static inline const char* password_string(const wifi_sta_config_t* sta) {
UINT_TO_STRING(sta->password);
}
static inline const char* ap_ssid_string(const wifi_ap_record_t* ap) { UINT_TO_STRING(ap->ssid); }
bool network_wifi_reset_rssi() {
ESP_LOGD(TAG,"Resetting RSSI");
if (network_status_lock_structure(pdMS_TO_TICKS(1000))) {
for (int index = 0; index < platform->net.credentials_count - 1; index++) {
platform->net.credentials[index].rssi = 0;
}
network_status_unlock_structure();
return true;
}
return false;
}
bool network_wifi_reset_connected() {
ESP_LOGD(TAG,"Resetting Connected");
if (network_status_lock_structure(pdMS_TO_TICKS(1000))) {
for (int index = 0; index < platform->net.credentials_count - 1; index++) {
platform->net.credentials[index].connected = false;
}
network_status_unlock_structure();
return true;
}
return false;
}
void network_wifi_format_bssid(char* buffer, size_t len, const uint8_t* bssid) {
snprintf(buffer, len, "%02X:%02X:%02X:%02X:%02X:%02X", bssid[0], bssid[1], bssid[2], bssid[3],
bssid[4], bssid[5]);
}
int network_wifi_get_ap_entry_index(const char* ssid) {
for (int i = 0; i < platform->net.credentials_count; i++) {
if (strcmp(platform->net.credentials[i].ssid, ssid) == 0) {
// found the SSID.
return i;
}
}
return -1;
}
sys_WifiSTAEntry * network_wifi_get_ap_entry(const char * ssid){
sys_WifiSTAEntry * result = NULL;
int index = network_wifi_get_ap_entry_index(ssid);
if(index>=0 && index < platform->net.credentials_count){
result = &platform->net.credentials[index];
}
return result;
}
void network_wifi_update_connected(const char * ssid){
if(!ssid || strlen(ssid) == 0){
ESP_LOGE(TAG, "Unable to update connected SSID. No ssid received");
return;
}
sys_WifiSTAEntry * sta = network_wifi_get_ap_entry(ssid);
if (sta && network_status_lock_structure(pdMS_TO_TICKS(1000))) {
sta->connected = true;
network_status_unlock_structure();
platform->net.has_last_connected = true;
memcpy(&platform->net.last_connected, sta,sizeof(platform->net.last_connected));
}
}
size_t network_wifi_get_known_count(){
size_t result = 0;
for (int i = 0; i < platform->net.credentials_count; i++) {
if(strlen(platform->net.credentials[i].ssid)>0) result ++;
}
return result;
}
bool network_wifi_remove_credentials(int index) {
int cur_index = 0;
if (index == -1 || index >= platform->net.credentials_count) {
ESP_LOGW(TAG, "ssid not found or erorr finding SSID");
return false;
}
if (network_status_lock_structure(pdMS_TO_TICKS(1000))) {
for (cur_index = index; cur_index < platform->net.credentials_count - 1; cur_index++) {
// Shift following ssid's starting at this slot.
memcpy(&platform->net.credentials[cur_index], &platform->net.credentials[cur_index + 1],
sizeof(sys_WifiSTAEntry));
}
memset(&platform->net.credentials[cur_index + 1], 0x00, sizeof(sys_WifiSTAEntry));
platform->net.credentials_count--;
network_status_unlock_structure();
return true;
}
return false;
}
bool network_wifi_remove_ap_entry(const char* ssid) {
int index = network_wifi_get_ap_entry_index(ssid);
return network_wifi_remove_credentials(index);
}
void network_wifi_sort_last_seen() {
sys_NetworkConfig* config = NULL;
if (!SYS_NET(config)) return;
if (network_status_lock_structure(pdMS_TO_TICKS(1000))) {
bool swapped;
do {
swapped = false;
for (int i = 0; i < config->credentials_count - 1; i++) {
if (config->credentials[i].last_seen.seconds < config->credentials[i + 1].last_seen.seconds) {
sys_WifiSTAEntry temp = config->credentials[i];
config->credentials[i] = config->credentials[i + 1];
config->credentials[i + 1] = temp;
swapped = true;
}
}
} while (swapped);
network_status_unlock_structure();
}
}
void network_wifi_sort_strength() {
sys_NetworkConfig* config = platform->has_net ? &platform->net : NULL;
if (!config) return;
if (network_status_lock_structure(pdMS_TO_TICKS(1000))) {
bool swapped;
do {
swapped = false;
for (int i = 0; i < config->credentials_count - 1; i++) {
if (config->credentials[i].rssi < config->credentials[i + 1].rssi) {
sys_WifiSTAEntry temp = config->credentials[i];
config->credentials[i] = config->credentials[i + 1];
config->credentials[i + 1] = temp;
swapped = true;
}
}
} while (swapped);
network_status_unlock_structure();
}
}
void network_wifi_empty_known_list() {
sys_WifiSTAEntry defaultWifi = sys_WifiSTAEntry_init_default;
sys_NetworkConfig* config = platform->has_net ? &platform->net : NULL;
if (!config) return;
for (int i = 0; i < config->credentials_count - 1; i++) {
memcpy(&config->credentials[i], &defaultWifi, sizeof(config->credentials[i]));
}
config->credentials_count = 0;
}
const wifi_sta_config_t* network_wifi_get_active_config() {
static wifi_config_t config;
esp_err_t err = ESP_OK;
memset(&config, 0x00, sizeof(config));
if ((err = esp_wifi_get_config(WIFI_IF_STA, &config)) == ESP_OK) {
return &config.sta;
} else {
ESP_LOGD(TAG, "Could not get wifi STA config: %s", esp_err_to_name(err));
}
return NULL;
}
sys_WifiSTAEntry* network_wifi_get_free_ssid() {
for (int i = 0; i < MAX_CREDENTIALS; i++) {
if (strlen(platform->net.credentials[i].ssid) == 0) {
return &platform->net.credentials[i];
}
}
return NULL;
}
bool network_wifi_add_ap(sys_WifiSTAEntry* item) {
sys_WifiSTAEntry* entry = network_wifi_get_free_ssid();
if (!entry) {
network_wifi_sort_last_seen();
network_wifi_remove_credentials(MAX_CREDENTIALS - 1);
platform->net.credentials_count--;
entry = network_wifi_get_free_ssid();
}
if (!entry) {
ESP_LOGE(TAG, "Unable to find free slot to store wifi");
return false;
}
memcpy(entry, item, sizeof(sys_WifiSTAEntry));
platform->net.credentials_count++;
return true;
}
sys_WifiSTAEntry* network_wifi_get_ssid_info(const char* ssid) {
if (!ssid || strlen(ssid) == 0) return NULL;
for (int i = 0; i < status.net.wifi.scan_result_count; i++) {
if (strcmp(status.net.wifi.scan_result[i].ssid, ssid) == 0) {
return &status.net.wifi.scan_result[i];
}
}
return NULL;
}
wifi_auth_mode_t network_wifi_get_auth_mode(sys_WifiAuthTypeEnum auth_type) {
switch (auth_type) {
case sys_WifiAuthTypeEnum_AUTH_OPEN:
return WIFI_AUTH_OPEN;
case sys_WifiAuthTypeEnum_AUTH_WEP:
return WIFI_AUTH_WEP;
case sys_WifiAuthTypeEnum_AUTH_WPA_PSK:
return WIFI_AUTH_WPA_PSK;
case sys_WifiAuthTypeEnum_AUTH_WPA2_PSK:
return WIFI_AUTH_WPA2_PSK;
case sys_WifiAuthTypeEnum_AUTH_WPA_WPA2_PSK:
return WIFI_AUTH_WPA_WPA2_PSK;
case sys_WifiAuthTypeEnum_AUTH_WPA2_ENTERPRISE:
return WIFI_AUTH_WPA2_ENTERPRISE;
case sys_WifiAuthTypeEnum_AUTH_WPA3_PSK:
return WIFI_AUTH_WPA3_PSK;
case sys_WifiAuthTypeEnum_AUTH_WPA2_WPA3_PSK:
return WIFI_AUTH_WPA2_WPA3_PSK;
case sys_WifiAuthTypeEnum_AUTH_WAPI_PSK:
return WIFI_AUTH_WAPI_PSK;
default:
return WIFI_AUTH_OPEN; // Default case
}
}
sys_WifiAuthTypeEnum network_wifi_get_auth_type(const wifi_auth_mode_t mode) {
switch (mode) {
case WIFI_AUTH_OPEN:
return sys_WifiAuthTypeEnum_AUTH_OPEN;
case WIFI_AUTH_WEP:
return sys_WifiAuthTypeEnum_AUTH_WEP;
case WIFI_AUTH_WPA_PSK:
return sys_WifiAuthTypeEnum_AUTH_WPA_PSK;
case WIFI_AUTH_WPA2_PSK:
return sys_WifiAuthTypeEnum_AUTH_WPA2_PSK;
case WIFI_AUTH_WPA_WPA2_PSK:
return sys_WifiAuthTypeEnum_AUTH_WPA_WPA2_PSK;
case WIFI_AUTH_WPA2_ENTERPRISE:
return sys_WifiAuthTypeEnum_AUTH_WPA2_ENTERPRISE;
case WIFI_AUTH_WPA3_PSK:
return sys_WifiAuthTypeEnum_AUTH_WPA3_PSK;
case WIFI_AUTH_WPA2_WPA3_PSK:
return sys_WifiAuthTypeEnum_AUTH_WPA2_WPA3_PSK;
case WIFI_AUTH_WAPI_PSK:
return sys_WifiAuthTypeEnum_AUTH_WAPI_PSK;
case WIFI_AUTH_MAX:
return sys_WifiAuthTypeEnum_AUTH_OPEN;
}
return sys_WifiAuthTypeEnum_AUTH_UNKNOWN;
}
sys_WifiRadioTypesEnum network_wifi_get_radio_type(const wifi_ap_record_t* sta) {
if (sta == NULL) {
return sys_WifiRadioTypesEnum_PHY_UNKNOWN;
}
// Check each bit field and return the corresponding enum value
if (sta->phy_11b) {
return sys_WifiRadioTypesEnum_PHY_11B;
} else if (sta->phy_11g) {
return sys_WifiRadioTypesEnum_PHY_11G;
} else if (sta->phy_11n) {
return sys_WifiRadioTypesEnum_PHY_11N;
} else if (sta->phy_lr) {
return sys_WifiRadioTypesEnum_PHY_LR;
} else if (sta->wps) {
return sys_WifiRadioTypesEnum_PHY_WPS;
} else if (sta->ftm_responder) {
return sys_WifiRadioTypesEnum_PHY_FTM_RESPONDER;
} else if (sta->ftm_initiator) {
return sys_WifiRadioTypesEnum_PHY_FTM_INITIATOR;
}
return sys_WifiRadioTypesEnum_PHY_UNKNOWN;
}
esp_err_t network_wifi_add_update_ap_from_sta_copy(const wifi_sta_config_t* sta) {
esp_err_t err = ESP_OK;
if (!sta) {
ESP_LOGE(TAG, "Invalid access point entry");
return ESP_ERR_INVALID_ARG;
}
if (!sta->ssid || strlen((char*)sta->ssid) == 0) {
ESP_LOGE(TAG, "Invalid access point ssid");
return ESP_ERR_INVALID_ARG;
}
sys_WifiSTAEntry item = sys_WifiSTAEntry_init_default;
strncpy(item.ssid, ssid_string(sta), sizeof(item.ssid));
strncpy(item.password, password_string(sta), sizeof(item.ssid));
network_wifi_format_bssid(item.bssid, sizeof(item.bssid), sta->bssid);
item.channel = sta->channel;
sys_WifiSTAEntry* seen = network_wifi_get_ssid_info(item.ssid);
if (seen) {
item.auth_type = seen->auth_type;
item.radio_type = seen->radio_type;
}
err = network_wifi_add_ap(&item);
return err;
}
bool network_wifi_is_known_ap(const char* ssid) { return network_wifi_get_ap_entry(ssid) != NULL; }
bool network_wifi_str2mac(const char* mac, uint8_t* values) {
if (6 == sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &values[0], &values[1], &values[2],
&values[3], &values[4], &values[5])) {
return true;
} else {
return false;
}
}
esp_err_t network_wifi_erase_known_ap() {
network_wifi_empty_known_list();
return ESP_OK;
}
esp_netif_t* network_wifi_get_interface() { return wifi_netif; }
esp_netif_t* network_wifi_get_ap_interface() { return wifi_ap_netif; }
esp_err_t network_wifi_set_sta_mode() {
if (!wifi_netif) {
ESP_LOGE(TAG, "Wifi not initialized. Cannot set sta mode");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGD(TAG, "Set Mode to STA");
esp_err_t err = esp_wifi_set_mode(WIFI_MODE_STA);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error setting mode to STA: %s", esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "Starting wifi");
err = esp_wifi_start();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error starting wifi: %s", esp_err_to_name(err));
}
}
return err;
}
esp_netif_t* network_wifi_start() {
MEMTRACE_PRINT_DELTA_MESSAGE("Starting wifi interface as STA mode");
if (!wifi_netif) {
MEMTRACE_PRINT_DELTA_MESSAGE("Init STA mode - creating default interface. ");
wifi_netif = esp_netif_create_default_wifi_sta();
MEMTRACE_PRINT_DELTA_MESSAGE("Initializing Wifi. ");
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_init(&cfg));
MEMTRACE_PRINT_DELTA_MESSAGE("Registering wifi Handlers");
// network_wifi_register_handlers();
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_instance_register(
WIFI_EVENT, ESP_EVENT_ANY_ID, &network_wifi_event_handler, NULL, NULL));
MEMTRACE_PRINT_DELTA_MESSAGE("Setting up wifi Storage");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_set_storage(WIFI_STORAGE_RAM));
}
MEMTRACE_PRINT_DELTA_MESSAGE("Setting up wifi mode as STA");
network_wifi_set_sta_mode();
MEMTRACE_PRINT_DELTA_MESSAGE("Setting hostname");
network_set_hostname(wifi_netif);
MEMTRACE_PRINT_DELTA_MESSAGE("Done starting wifi interface");
return wifi_netif;
}
void destroy_network_wifi() {
}
bool network_wifi_sta_config_changed() {
bool changed = true;
const wifi_sta_config_t* sta = network_wifi_get_active_config();
if (!sta || strlen(ssid_string(sta)) == 0) return false;
sys_WifiSTAEntry* known = network_wifi_get_ap_entry(ssid_string(sta));
if (known && strcmp(known->ssid, ssid_string(sta)) == 0 &&
strcmp((char*)known->password, password_string(sta)) == 0) {
changed = false;
} else {
ESP_LOGI(TAG, "New network configuration found");
}
return changed;
}
static void network_wifi_event_handler(
void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if (event_base != WIFI_EVENT) return;
switch (event_id) {
case WIFI_EVENT_WIFI_READY:
ESP_LOGD(TAG, "WIFI_EVENT_WIFI_READY");
break;
case WIFI_EVENT_SCAN_DONE:
ESP_LOGD(TAG, "WIFI_EVENT_SCAN_DONE");
network_async_scan_done();
break;
case WIFI_EVENT_STA_AUTHMODE_CHANGE:
ESP_LOGD(TAG, "WIFI_EVENT_STA_AUTHMODE_CHANGE");
break;
case WIFI_EVENT_AP_START:
ESP_LOGD(TAG, "WIFI_EVENT_AP_START");
break;
case WIFI_EVENT_AP_STOP:
ESP_LOGD(TAG, "WIFI_EVENT_AP_STOP");
break;
case WIFI_EVENT_AP_PROBEREQRECVED: {
wifi_event_ap_probe_req_rx_t* s = (wifi_event_ap_probe_req_rx_t*)event_data;
char* mac = network_manager_alloc_get_mac_string(s->mac);
if (mac) {
ESP_LOGD(
TAG, "WIFI_EVENT_AP_PROBEREQRECVED. RSSI: %d, MAC: %s", s->rssi, STR_OR_BLANK(mac));
}
FREE_AND_NULL(mac);
} break;
case WIFI_EVENT_STA_WPS_ER_SUCCESS:
ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS");
break;
case WIFI_EVENT_STA_WPS_ER_FAILED:
ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");
break;
case WIFI_EVENT_STA_WPS_ER_TIMEOUT:
ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_TIMEOUT");
break;
case WIFI_EVENT_STA_WPS_ER_PIN:
ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_PIN");
break;
case WIFI_EVENT_AP_STACONNECTED: {
wifi_event_ap_staconnected_t* stac = (wifi_event_ap_staconnected_t*)event_data;
char* mac = network_manager_alloc_get_mac_string(stac->mac);
if (mac) {
ESP_LOGD(
TAG, "WIFI_EVENT_AP_STACONNECTED. aid: %d, mac: %s", stac->aid, STR_OR_BLANK(mac));
}
FREE_AND_NULL(mac);
} break;
case WIFI_EVENT_AP_STADISCONNECTED:
ESP_LOGD(TAG, "WIFI_EVENT_AP_STADISCONNECTED");
break;
case WIFI_EVENT_STA_START:
ESP_LOGD(TAG, "WIFI_EVENT_STA_START");
break;
case WIFI_EVENT_STA_STOP:
ESP_LOGD(TAG, "WIFI_EVENT_STA_STOP");
break;
case WIFI_EVENT_STA_CONNECTED: {
ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. ");
wifi_event_sta_connected_t* s = (wifi_event_sta_connected_t*)event_data;
char* bssid = network_manager_alloc_get_mac_string(s->bssid);
char* ssid = strdup_psram((char*)s->ssid);
if (bssid && ssid) {
ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. Channel: %d, Access point: %s, BSSID: %s ",
s->channel, STR_OR_BLANK(ssid), (bssid));
network_wifi_update_connected(ssid);
}
FREE_AND_NULL(bssid);
FREE_AND_NULL(ssid);
network_async(EN_CONNECTED);
} break;
case WIFI_EVENT_STA_DISCONNECTED: {
// structwifi_event_sta_disconnected_t
// Argument structure for WIFI_EVENT_STA_DISCONNECTED event
//
// Public Members
//
// uint8_t ssid[32]
// SSID of disconnected AP
//
// uint8_t ssid_len
// SSID length of disconnected AP
//
// uint8_t bssid[6]
// BSSID of disconnected AP
//
// uint8_t reason
// reason of disconnection
wifi_event_sta_disconnected_t* s = (wifi_event_sta_disconnected_t*)event_data;
char* bssid = network_manager_alloc_get_mac_string(s->bssid);
ESP_LOGW(TAG, "WIFI_EVENT_STA_DISCONNECTED. From BSSID: %s, reason code: %d (%s)",
STR_OR_BLANK(bssid), s->reason, get_disconnect_code_desc(s->reason));
FREE_AND_NULL(bssid);
if (s->reason == WIFI_REASON_ROAMING) {
ESP_LOGI(TAG, "WiFi Roaming to new access point");
} else {
network_async_lost_connection((wifi_event_sta_disconnected_t*)event_data);
}
} break;
default:
break;
}
}
void network_wifi_write_file(const char * filename, sys_Status * status_struct){
FILE* file = open_file("wb", filename);
pb_ostream_t filestream = {&out_file_binding, file, SIZE_MAX, 0};
ESP_LOGD(TAG, "Starting encode");
if (!pb_encode(&filestream, sys_Config_fields, (void*)&status)) {
ESP_LOGE(TAG, "Encoding failed: %s\n", PB_GET_ERROR(&filestream));
}
fclose(file);
}
void network_wifi_global_init() {
pb_istream_t istream =PB_ISTREAM_EMPTY;
ESP_LOGD(TAG, "Loading existing wifi configuration (if any)");
FILE* file = open_file("rb", status_file_name);
if (!file) {
network_wifi_write_file(status_file_name,&status);
file = open_file("rb", status_file_name);
}
if (!file) {
ESP_LOGE(TAG, "Unable to read status file");
return;
}
istream.callback = &in_file_binding;
istream.state = file;
pb_decode(&istream, &sys_Status_msg, &status);
fclose(file);
}
esp_netif_t* network_wifi_config_ap() {
esp_netif_ip_info_t info;
esp_err_t err = ESP_OK;
wifi_config_t ap_config = {
.ap = {.ssid_len = 0,
.authmode = AP_AUTHMODE,
.ssid_hidden = DEFAULT_AP_SSID_HIDDEN,
.max_connection = DEFAULT_AP_MAX_CONNECTIONS,
.beacon_interval = DEFAULT_AP_BEACON_INTERVAL
},
};
ESP_LOGI(TAG, "Configuring Access Point.");
if (!wifi_ap_netif) {
wifi_ap_netif = esp_netif_create_default_wifi_ap();
}
if (platform->has_net && platform->net.has_ap && platform->net.ap.has_ip) {
inet_pton(AF_INET, platform->net.ap.ip.ip,
(ip4_addr_t*)&info.ip); /* access point is on a static IP */
inet_pton(AF_INET, platform->net.ap.ip.gw,
(ip4_addr_t*)&info.gw); /* access point is on a static IP */
inet_pton(AF_INET, platform->net.ap.ip.netmask,
(ip4_addr_t*)&info.netmask); /* access point is on a static IP */
} else {
inet_pton(
AF_INET, DEFAULT_AP_IP, (ip4_addr_t*)&info.ip); /* access point is on a static IP */
inet_pton(AF_INET, CONFIG_DEFAULT_AP_GATEWAY,
(ip4_addr_t*)&info.gw); /* access point is on a static IP */
inet_pton(AF_INET, CONFIG_DEFAULT_AP_NETMASK,
(ip4_addr_t*)&info.netmask); /* access point is on a st */
}
/* In order to change the IP info structure, we have to first stop
* the DHCP server on the new interface
*/
network_start_stop_dhcps(wifi_ap_netif, false);
ESP_LOGD(TAG, "Setting tcp_ip info for access point");
if ((err = esp_netif_set_ip_info(wifi_ap_netif, &info)) != ESP_OK) {
ESP_LOGE(TAG, "Setting tcp_ip info for interface TCPIP_ADAPTER_IF_AP. Error %s",
esp_err_to_name(err));
return wifi_ap_netif;
}
network_start_stop_dhcps(wifi_ap_netif, true);
/*
* Set Access Point configuration
*/
const char* ap_ssid = CONFIG_DEFAULT_AP_SSID;
if (platform->has_names && strlen(platform->names.wifi_ap_name) > 0) {
ap_ssid = platform->names.wifi_ap_name;
}
const char* ap_password = DEFAULT_AP_PASSWORD;
ap_config.ap.channel = CONFIG_DEFAULT_AP_CHANNEL;
if (platform->has_net && platform->net.has_ap) {
if (strlen(platform->net.ap.password) > 0) {
ap_password = platform->net.ap.password;
}
if (platform->net.ap.channel > 0) {
ap_config.ap.channel = platform->net.ap.channel;
}
if (platform->net.ap.auth_mode != sys_WifiAuthTypeEnum_AUTH_UNKNOWN) {
ap_config.ap.authmode = network_wifi_get_auth_mode(platform->net.ap.auth_mode);
}
ap_config.ap.ssid_hidden = platform->net.ap.hidden;
if (platform->net.ap.max_connection > 0) {
ap_config.ap.max_connection = platform->net.ap.max_connection;
}
if (platform->net.ap.beacon_interval > 0) {
ap_config.ap.beacon_interval = platform->net.ap.beacon_interval;
}
}
strlcpy((char*)ap_config.ap.ssid, ap_ssid, sizeof(ap_config.ap.ssid));
strlcpy((char*)ap_config.ap.password, ap_password, sizeof(ap_config.ap.password));
ESP_LOGI(TAG,
"AP SSID: %s, PASSWORD: %s Auth Mode: %d SSID: %s Max Connections: %d Beacon interval: %d",
(char*)ap_config.ap.ssid, (char*)ap_config.ap.password, ap_config.ap.authmode,
ap_config.ap.ssid_hidden ? "HIDDEN" : "VISIBLE", ap_config.ap.max_connection,
ap_config.ap.beacon_interval);
const char* msg = "Setting wifi mode as WIFI_MODE_APSTA";
ESP_LOGD(TAG, "%s", msg);
if ((err = esp_wifi_set_mode(WIFI_MODE_APSTA)) != ESP_OK) {
ESP_LOGE(TAG, "%s. Error %s", msg, esp_err_to_name(err));
return wifi_ap_netif;
}
msg = "Setting wifi AP configuration for WIFI_IF_AP";
ESP_LOGD(TAG, "%s", msg);
if ((err = esp_wifi_set_config(WIFI_IF_AP, &ap_config)) != ESP_OK) /* stop AP DHCP server */
{
ESP_LOGE(TAG, "%s . Error %s", msg, esp_err_to_name(err));
return wifi_ap_netif;
}
msg = "Setting wifi bandwidth";
ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_AP_BANDWIDTH);
if ((err = esp_wifi_set_bandwidth(WIFI_IF_AP, DEFAULT_AP_BANDWIDTH)) != ESP_OK) /* stop AP
DHCP server */
{
ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err));
return wifi_ap_netif;
}
msg = "Setting wifi power save";
ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_STA_POWER_SAVE);
if ((err = esp_wifi_set_ps(DEFAULT_STA_POWER_SAVE)) != ESP_OK) /* stop AP DHCP server */
{
ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err));
return wifi_ap_netif;
}
ESP_LOGD(TAG, "Done configuring Soft Access Point");
return wifi_ap_netif;
}
void network_wifi_filter_unique(wifi_ap_record_t* aplist, uint16_t* aps) {
int total_unique;
wifi_ap_record_t* first_free;
total_unique = *aps;
first_free = NULL;
for (int i = 0; i < *aps - 1; i++) {
wifi_ap_record_t* ap = &aplist[i];
/* skip the previously removed APs */
if (ap->ssid[0] == 0) continue;
/* remove the identical SSID+authmodes */
for (int j = i + 1; j < *aps; j++) {
wifi_ap_record_t* ap1 = &aplist[j];
if ((strcmp((const char*)ap->ssid, (const char*)ap1->ssid) == 0) &&
(ap->authmode == ap1->authmode)) { /* same SSID, different auth mode is skipped */
/* save the rssi for the display */
if ((ap1->rssi) > (ap->rssi)) ap->rssi = ap1->rssi;
/* clearing the record */
memset(ap1, 0, sizeof(wifi_ap_record_t));
}
}
}
/* reorder the list so APs follow each other in the list */
for (int i = 0; i < *aps; i++) {
wifi_ap_record_t* ap = &aplist[i];
/* skipping all that has no name */
if (ap->ssid[0] == 0) {
/* mark the first free slot */
if (first_free == NULL) first_free = ap;
total_unique--;
continue;
}
if (first_free != NULL) {
memcpy(first_free, ap, sizeof(wifi_ap_record_t));
memset(ap, 0, sizeof(wifi_ap_record_t));
/* find the next free slot */
for (int j = 0; j < *aps; j++) {
if (aplist[j].ssid[0] == 0) {
first_free = &aplist[j];
break;
}
}
}
}
/* update the length of the list */
*aps = total_unique;
}
void network_wifi_clear_scan_results() {
if (!status.net.wifi.scan_result || status.net.wifi.scan_result_count == 0) {
return;
}
free(status.net.wifi.scan_result);
status.net.wifi.scan_result = NULL;
status.net.wifi.scan_result_count = 0;
}
sys_WifiSTAEntry* network_wifi_alloc_scan_results(uint16_t count) {
network_wifi_clear_scan_results();
status.net.wifi.scan_result = malloc_init_external(count * sizeof(sys_WifiSTAEntry));
status.net.wifi.scan_result_count = count;
return status.net.wifi.scan_result;
}
void network_wifi_esp_sta_to_sta(wifi_ap_record_t* scan_res, sys_WifiSTAEntry* sta_entry) {
if(!sta_entry){
return;
}
sta_entry->radio_type = network_wifi_get_radio_type(scan_res);
sta_entry->auth_type = network_wifi_get_auth_type(scan_res->authmode);
network_wifi_format_bssid(sta_entry->bssid, sizeof(sta_entry->bssid), scan_res->bssid);
sta_entry->channel = scan_res->primary;
gettimeofday((struct timeval*)&sta_entry->last_seen, NULL);
sta_entry->rssi = scan_res->rssi;
strncpy(sta_entry->ssid, ap_ssid_string(scan_res), sizeof(sta_entry->ssid));
// also update any existing credential entry if any
network_wifi_esp_sta_to_sta(scan_res,network_wifi_get_ap_entry(sta_entry->ssid));
}
bool network_wifi_update_scan_list(wifi_ap_record_t* accessp_records, uint16_t count) {
if (!network_wifi_alloc_scan_results(count)) {
ESP_LOGE(TAG, "Error allocating memory to store scan results");
return false;
}
// reset RSSI values. This will help when choosing the
// strongest signal to connect to
network_wifi_reset_rssi();
for (int i = 0; i < status.net.wifi.scan_result_count; i++) {
network_wifi_esp_sta_to_sta(&accessp_records[i], &status.net.wifi.scan_result[i]);
}
network_wifi_sort_strength();
return true;
}
esp_err_t wifi_scan_done() {
esp_err_t err = ESP_OK;
wifi_ap_record_t* accessp_records = NULL;
/* As input param, it stores max AP number ap_records can hold. As output param, it receives the
* actual AP number this API returns. As a consequence, ap_num MUST be reset to MAX_AP_NUM at
* every scan */
ESP_LOGD(TAG, "Getting AP list records");
uint16_t ap_num = MAX_AP_NUM;
if ((err = esp_wifi_scan_get_ap_num(&ap_num)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to retrieve scan results count. Error %s", esp_err_to_name(err));
return err;
}
if (ap_num <= 0) {
ESP_LOGI(TAG, "No AP found during scan");
return err;
}
accessp_records = (wifi_ap_record_t*)malloc_init_external(sizeof(wifi_ap_record_t) * ap_num);
if (!accessp_records) {
ESP_LOGE(TAG, "Alloc failed for scan results");
return ESP_FAIL;
}
if ((err = esp_wifi_scan_get_ap_records(&ap_num, accessp_records)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to retrieve scan results list. Error %s", esp_err_to_name(err));
} else {
/* make sure the http server isn't trying to access the list while it gets refreshed */
ESP_LOGD(TAG, "Retrieving scan list");
/* Will remove the duplicate SSIDs from the list and update ap_num */
network_wifi_filter_unique(accessp_records, &ap_num);
if (network_status_lock_structure(pdMS_TO_TICKS(1000))) {
network_wifi_update_scan_list(accessp_records, ap_num);
network_status_unlock_structure();
ESP_LOGD(TAG, "Done retrieving scan list");
} else {
ESP_LOGE(TAG, "could not get access to json mutex in wifi_scan");
err = ESP_FAIL;
}
}
free(accessp_records);
return err;
}
bool is_wifi_up() { return wifi_netif != NULL; }
esp_err_t network_wifi_start_scan() {
wifi_scan_config_t scan_config = {.ssid = 0,
.bssid = 0,
.channel = 0,
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.show_hidden = true};
esp_err_t err = ESP_OK;
ESP_LOGI(TAG, "Initiating wifi network scan");
if (!is_wifi_up()) {
messaging_post_message(
MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot scan");
return ESP_FAIL;
}
/* if a scan is already in progress this message is simply ignored thanks to the
* WIFI_MANAGER_SCAN_BIT uxBit */
if ((err = esp_wifi_scan_start(&scan_config, false)) != ESP_OK) {
ESP_LOGW(TAG, "Unable to start scan; %s ", esp_err_to_name(err));
// set_status_message(WARNING, "Wifi Connecting. Cannot start scan.");
messaging_post_message(
MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Scanning failed: %s", esp_err_to_name(err));
}
return err;
}
bool network_wifi_is_ap_mode() {
wifi_mode_t mode;
/* update config to latest and attempt connection */
return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_AP;
}
bool network_wifi_is_sta_mode() {
wifi_mode_t mode;
/* update config to latest and attempt connection */
return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_STA;
}
bool network_wifi_is_ap_sta_mode() {
wifi_mode_t mode;
/* update config to latest and attempt connection */
return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_APSTA;
}
esp_err_t network_wifi_connect(const char* ssid, const char* password) {
esp_err_t err = ESP_OK;
wifi_config_t config;
memset(&config, 0x00, sizeof(config));
ESP_LOGD(TAG, "network_wifi_connect");
network_wifi_reset_connected();
if (!is_wifi_up()) {
messaging_post_message(
MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot connect");
return ESP_FAIL;
}
if (!ssid || !password || strlen(ssid) == 0) {
ESP_LOGE(TAG, "Cannot connect wifi. wifi config is null!");
return ESP_ERR_INVALID_ARG;
}
wifi_mode_t wifi_mode;
err = esp_wifi_get_mode(&wifi_mode);
if (err == ESP_ERR_WIFI_NOT_INIT) {
ESP_LOGW(TAG, "Wifi not initialized. Attempting to start sta mode");
network_wifi_start();
} else if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not retrieve wifi mode : %s", esp_err_to_name(err));
} else if (wifi_mode != WIFI_MODE_STA && wifi_mode != WIFI_MODE_APSTA) {
ESP_LOGD(TAG, "Changing wifi mode to STA");
err = network_wifi_set_sta_mode();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not set mode to STA. Cannot connect to SSID %s", ssid);
return err;
}
}
// copy configuration and connect
strlcpy((char*)config.sta.ssid, ssid, sizeof(config.sta.ssid));
if (password) {
strlcpy((char*)config.sta.password, password, sizeof(config.sta.password));
}
// First Disconnect
esp_wifi_disconnect();
config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
if ((err = esp_wifi_set_config(WIFI_IF_STA, &config)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to set STA configuration. Error %s", esp_err_to_name(err));
}
if (err == ESP_OK) {
ESP_LOGI(TAG, "Wifi Connecting to %s...", ssid);
if ((err = esp_wifi_connect()) != ESP_OK) {
ESP_LOGE(TAG, "Failed to initiate wifi connection. Error %s", esp_err_to_name(err));
}
}
return err;
}
esp_err_t network_wifi_connect_ssid(const char* ssid) {
sys_WifiSTAEntry* item = network_wifi_get_ssid_info(ssid);
if (item) {
gettimeofday((struct timeval*)&item->last_try, NULL);
return network_wifi_connect(item->ssid, item->password);
}
return ESP_FAIL;
}
esp_err_t network_wifi_connect_active_ssid() {
sys_WifiSTAEntry*connected = NULL;
if(status.has_net && platform->net.has_last_connected && strlen(platform->net.last_connected.ssid)>0){
connected = &platform->net.last_connected.ssid;
return network_wifi_connect(connected->ssid,connected->password);
}
return ESP_FAIL;
}
void network_wifi_clear_config() {
/* erase configuration */
const wifi_sta_config_t* sta = network_wifi_get_active_config();
network_wifi_remove_ap_entry(ssid_string(sta));
esp_err_t err = ESP_OK;
if ((err = esp_wifi_disconnect()) != ESP_OK) {
ESP_LOGW(TAG, "Could not disconnect from deleted network : %s", esp_err_to_name(err));
}
}
char* get_disconnect_code_desc(uint8_t reason) {
switch (reason) {
ENUM_TO_STRING(WIFI_REASON_UNSPECIFIED);
ENUM_TO_STRING(WIFI_REASON_AUTH_EXPIRE);
ENUM_TO_STRING(WIFI_REASON_AUTH_LEAVE);
ENUM_TO_STRING(WIFI_REASON_ASSOC_EXPIRE);
ENUM_TO_STRING(WIFI_REASON_ASSOC_TOOMANY);
ENUM_TO_STRING(WIFI_REASON_NOT_AUTHED);
ENUM_TO_STRING(WIFI_REASON_NOT_ASSOCED);
ENUM_TO_STRING(WIFI_REASON_ASSOC_LEAVE);
ENUM_TO_STRING(WIFI_REASON_ASSOC_NOT_AUTHED);
ENUM_TO_STRING(WIFI_REASON_DISASSOC_PWRCAP_BAD);
ENUM_TO_STRING(WIFI_REASON_DISASSOC_SUPCHAN_BAD);
ENUM_TO_STRING(WIFI_REASON_IE_INVALID);
ENUM_TO_STRING(WIFI_REASON_MIC_FAILURE);
ENUM_TO_STRING(WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT);
ENUM_TO_STRING(WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT);
ENUM_TO_STRING(WIFI_REASON_IE_IN_4WAY_DIFFERS);
ENUM_TO_STRING(WIFI_REASON_GROUP_CIPHER_INVALID);
ENUM_TO_STRING(WIFI_REASON_PAIRWISE_CIPHER_INVALID);
ENUM_TO_STRING(WIFI_REASON_AKMP_INVALID);
ENUM_TO_STRING(WIFI_REASON_UNSUPP_RSN_IE_VERSION);
ENUM_TO_STRING(WIFI_REASON_INVALID_RSN_IE_CAP);
ENUM_TO_STRING(WIFI_REASON_802_1X_AUTH_FAILED);
ENUM_TO_STRING(WIFI_REASON_CIPHER_SUITE_REJECTED);
ENUM_TO_STRING(WIFI_REASON_INVALID_PMKID);
ENUM_TO_STRING(WIFI_REASON_BEACON_TIMEOUT);
ENUM_TO_STRING(WIFI_REASON_NO_AP_FOUND);
ENUM_TO_STRING(WIFI_REASON_AUTH_FAIL);
ENUM_TO_STRING(WIFI_REASON_ASSOC_FAIL);
ENUM_TO_STRING(WIFI_REASON_HANDSHAKE_TIMEOUT);
ENUM_TO_STRING(WIFI_REASON_CONNECTION_FAIL);
ENUM_TO_STRING(WIFI_REASON_AP_TSF_RESET);
ENUM_TO_STRING(WIFI_REASON_ROAMING);
}
return "";
}