diff --git a/main/include/wifi_connection.h b/main/include/wifi_connection.h index 782e48d..12ac8fd 100644 --- a/main/include/wifi_connection.h +++ b/main/include/wifi_connection.h @@ -5,6 +5,15 @@ #include #include "esp_wifi.h" +#include "esp_wifi_types.h" +#include "esp_wpa2.h" + +#define WIFI_MCH2022_SSID "MCH2022" +#define WIFI_MCH2022_USER "mch2022" +#define WIFI_MCH2022_IDENT "mch2022" +#define WIFI_MCH2022_PASSWORD "mch2022" +#define WIFI_MCH2022_AUTH WIFI_AUTH_WPA2_ENTERPRISE +#define WIFI_MCH2022_PHASE2 ESP_EAP_TTLS_PHASE2_MSCHAPV2 // Simpler interpretation of WiFi signal strength. typedef enum { @@ -26,7 +35,7 @@ void wifi_init(); bool wifi_connect(const char* aSsid, const char* aPassword, wifi_auth_mode_t aAuthmode, uint8_t aRetryMax); // Connect to a WPA2 enterprise WiFi network. -bool wifi_connect_ent(const char* aSsid, const char *aIdent, const char *aAnonIdent, const char* aPassword, uint8_t aRetryMax); +bool wifi_connect_ent(const char* aSsid, const char *aIdent, const char *aAnonIdent, const char* aPassword, esp_eap_ttls_phase2_types phase2, uint8_t aRetryMax); // Scan for WiFi networks. // Updates the APs pointer if non-null. diff --git a/main/menus/wifi.c b/main/menus/wifi.c index b0774f0..962f40e 100644 --- a/main/menus/wifi.c +++ b/main/menus/wifi.c @@ -19,17 +19,44 @@ #include "system_wrapper.h" #include "bootscreen.h" #include "wifi_connect.h" +#include "wifi_connection.h" #include "wifi_ota.h" #include "graphics_wrapper.h" static const char *TAG = "wifi menu"; typedef enum action { + /* ==== GENERIC ACTIONS ==== */ + // Nothing happens. ACTION_NONE, + // Go back to the parent menu. ACTION_BACK, + + /* ==== MAIN MENU ACTIONS ==== */ + // Show the current WiFi settings. ACTION_SHOW, + // Scan for networks and pick one to connect to. ACTION_SCAN, - ACTION_MANUAL + // Manually edit the current WiFi settings. + ACTION_MANUAL, + + /* ==== AUTH MODES ==== */ + ACTION_AUTH_OPEN, + ACTION_AUTH_WEP, + ACTION_AUTH_WPA_PSK, + ACTION_AUTH_WPA2_PSK, + ACTION_AUTH_WPA_WPA2_PSK, + ACTION_AUTH_WPA2_ENTERPRISE, + ACTION_AUTH_WPA3_PSK, + ACTION_AUTH_WPA2_WPA3_PSK, + ACTION_AUTH_WAPI_PSK, + + /* ==== PHASE2 AUTH MODES ==== */ + ACTION_PHASE2_EAP, + ACTION_PHASE2_MSCHAPV2, + ACTION_PHASE2_MSCHAP, + ACTION_PHASE2_PAP, + ACTION_PHASE2_CHAP, } menu_wifi_action_t; void render_wifi_help(pax_buf_t* pax_buffer) { @@ -40,6 +67,9 @@ void render_wifi_help(pax_buf_t* pax_buffer) { void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); void wifi_setup(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, bool scan); +wifi_ap_record_t *wifi_scan_results(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, size_t num_aps, wifi_ap_record_t *aps); +int wifi_auth_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, wifi_auth_mode_t default_mode); +int wifi_phase2_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, esp_eap_ttls_phase2_types default_mode); void menu_wifi(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { menu_t* menu = menu_alloc("WiFi configuration"); @@ -137,10 +167,8 @@ void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341 char buffer[300]; pax_noclip(pax_buffer); pax_background(pax_buffer, 0xFFFFFF); - snprintf(buffer, sizeof(buffer), "SSID is %s", ssid); - pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 20*0, buffer); - snprintf(buffer, sizeof(buffer), "Password is %s", password); - pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 20*1, buffer); + snprintf(buffer, sizeof(buffer), "WiFi SSID:\n%s\nWiFi password:\n%s", ssid, password); + pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 0, buffer); ili9341_write(ili9341, pax_buffer->buf); bool quit = false; @@ -165,37 +193,347 @@ void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341 } } -void wifi_setup(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, bool scan) { - nvs_handle_t handle; - nvs_open("system", NVS_READWRITE, &handle); - char ssid[33]; - char password[33]; - size_t requiredSize; - esp_err_t res = nvs_get_str(handle, "wifi.ssid", NULL, &requiredSize); - if (res != ESP_OK) { - strcpy(ssid, ""); - strcpy(password, ""); - } else if (requiredSize < sizeof(ssid)) { - res = nvs_get_str(handle, "wifi.ssid", ssid, &requiredSize); - if (res != ESP_OK) strcpy(ssid, ""); - res = nvs_get_str(handle, "wifi.password", NULL, &requiredSize); - if (res != ESP_OK) { - strcpy(password, ""); - } else if (requiredSize < sizeof(password)) { - res = nvs_get_str(handle, "wifi.password", password, &requiredSize); - if (res != ESP_OK) strcpy(password, ""); +wifi_ap_record_t *wifi_scan_results(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, size_t num_aps, wifi_ap_record_t *aps) { + menu_t *menu = menu_alloc("Select network"); + wifi_ap_record_t *picked = NULL; + + render_wifi_help(pax_buffer); + + for (size_t i = 0; i < num_aps; i++) { + menu_insert_item(menu, (const char*) aps[i].ssid, NULL, (void *) (i + 1), -1); + } + + bool render = true; + size_t selection = 0; + while (1) { + rp2040_input_message_t buttonMessage = {0}; + selection = -1; + if (xQueueReceive(buttonQueue, &buttonMessage, 16 / portTICK_PERIOD_MS) == pdTRUE) { + uint8_t pin = buttonMessage.input; + bool value = buttonMessage.state; + switch(pin) { + case RP2040_INPUT_JOYSTICK_DOWN: + if (value) { + menu_navigate_next(menu); + render = true; + } + break; + case RP2040_INPUT_JOYSTICK_UP: + if (value) { + menu_navigate_previous(menu); + render = true; + } + break; + case RP2040_INPUT_BUTTON_HOME: + case RP2040_INPUT_BUTTON_BACK: + if (value) { + selection = 0; + } + break; + case RP2040_INPUT_BUTTON_ACCEPT: + case RP2040_INPUT_JOYSTICK_PRESS: + case RP2040_INPUT_BUTTON_SELECT: + case RP2040_INPUT_BUTTON_START: + if (value) { + selection = (size_t) menu_get_callback_args(menu, menu_get_position(menu)); + } + break; + default: + break; + } + } + + if (render) { + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF2f55a8); + ili9341_write(ili9341, pax_buffer->buf); + render = false; + } + + if (selection != (size_t) -1) { + if (selection == 0) { + break; + } else { + // You picked one, yay! + picked = &aps[selection-1]; + break; + } + render = true; + selection = -1; + render_wifi_help(pax_buffer); + } + } + + menu_free(menu); + return picked; +} + +int wifi_auth_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, wifi_auth_mode_t default_mode) { + menu_t* menu = menu_alloc("Authentication mode"); + menu_insert_item(menu, "Insecure", NULL, (void*) ACTION_AUTH_OPEN, -1); + menu_insert_item(menu, "WEP", NULL, (void*) ACTION_AUTH_WEP, -1); + menu_insert_item(menu, "WPA PSK", NULL, (void*) ACTION_AUTH_WPA_PSK, -1); + menu_insert_item(menu, "WPA2 PSK", NULL, (void*) ACTION_AUTH_WPA2_PSK, -1); + // menu_insert_item(menu, "QQQQQQQQQQQQ", NULL, (void*) ACTION_AUTH_WPA_WPA2_PSK, -1); + menu_insert_item(menu, "WPA2 Enterprise", NULL, (void*) ACTION_AUTH_WPA2_ENTERPRISE, -1); + menu_insert_item(menu, "WPA3 PSK", NULL, (void*) ACTION_AUTH_WPA3_PSK, -1); + // menu_insert_item(menu, "QQQQQQQQQQQQ", NULL, (void*) ACTION_AUTH_WPA2_WPA3_PSK, -1); + // menu_insert_item(menu, "WAPI PSK", NULL, (void*) ACTION_AUTH_WAPI_PSK, -1); + + bool render = true; + menu_wifi_action_t action = ACTION_NONE; + wifi_auth_mode_t pick = default_mode; + + render_wifi_help(pax_buffer); + + while (1) { + rp2040_input_message_t buttonMessage = {0}; + if (xQueueReceive(buttonQueue, &buttonMessage, 16 / portTICK_PERIOD_MS) == pdTRUE) { + uint8_t pin = buttonMessage.input; + bool value = buttonMessage.state; + switch(pin) { + case RP2040_INPUT_JOYSTICK_DOWN: + if (value) { + menu_navigate_next(menu); + render = true; + } + break; + case RP2040_INPUT_JOYSTICK_UP: + if (value) { + menu_navigate_previous(menu); + render = true; + } + break; + case RP2040_INPUT_BUTTON_HOME: + case RP2040_INPUT_BUTTON_BACK: + if (value) { + action = ACTION_BACK; + } + break; + case RP2040_INPUT_BUTTON_ACCEPT: + case RP2040_INPUT_JOYSTICK_PRESS: + case RP2040_INPUT_BUTTON_SELECT: + case RP2040_INPUT_BUTTON_START: + if (value) { + action = (menu_wifi_action_t) menu_get_callback_args(menu, menu_get_position(menu)); + } + break; + default: + break; + } + } + + if (render) { + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF2f55a8); + ili9341_write(ili9341, pax_buffer->buf); + render = false; + } + + if (action != ACTION_NONE) { + if (action == ACTION_BACK) { + break; + } else { + pick = (wifi_auth_mode_t) (action - ACTION_AUTH_OPEN); + break; + } + render = true; + action = ACTION_NONE; + render_wifi_help(pax_buffer); + } + } + + menu_free(menu); + return pick; +} + +int wifi_phase2_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, esp_eap_ttls_phase2_types default_mode) { + menu_t* menu = menu_alloc("Phase 2 authentication mode"); + menu_insert_item(menu, "ESP", NULL, (void*) ACTION_PHASE2_EAP, -1); + menu_insert_item(menu, "MSCHAPv2", NULL, (void*) ACTION_PHASE2_MSCHAPV2, -1); + menu_insert_item(menu, "MSCHAP", NULL, (void*) ACTION_PHASE2_MSCHAP, -1); + menu_insert_item(menu, "PAP", NULL, (void*) ACTION_PHASE2_PAP, -1); + menu_insert_item(menu, "CHAP", NULL, (void*) ACTION_PHASE2_CHAP, -1); + + bool render = true; + menu_wifi_action_t action = ACTION_NONE; + esp_eap_ttls_phase2_types pick = default_mode; + + render_wifi_help(pax_buffer); + + while (1) { + rp2040_input_message_t buttonMessage = {0}; + if (xQueueReceive(buttonQueue, &buttonMessage, 16 / portTICK_PERIOD_MS) == pdTRUE) { + uint8_t pin = buttonMessage.input; + bool value = buttonMessage.state; + switch(pin) { + case RP2040_INPUT_JOYSTICK_DOWN: + if (value) { + menu_navigate_next(menu); + render = true; + } + break; + case RP2040_INPUT_JOYSTICK_UP: + if (value) { + menu_navigate_previous(menu); + render = true; + } + break; + case RP2040_INPUT_BUTTON_HOME: + case RP2040_INPUT_BUTTON_BACK: + if (value) { + action = ACTION_BACK; + } + break; + case RP2040_INPUT_BUTTON_ACCEPT: + case RP2040_INPUT_JOYSTICK_PRESS: + case RP2040_INPUT_BUTTON_SELECT: + case RP2040_INPUT_BUTTON_START: + if (value) { + action = (menu_wifi_action_t) menu_get_callback_args(menu, menu_get_position(menu)); + } + break; + default: + break; + } + } + + if (render) { + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF2f55a8); + ili9341_write(ili9341, pax_buffer->buf); + render = false; + } + + if (action != ACTION_NONE) { + if (action == ACTION_BACK) { + break; + } else { + pick = (wifi_auth_mode_t) (action - ACTION_PHASE2_EAP); + break; + } + render = true; + action = ACTION_NONE; + render_wifi_help(pax_buffer); + } + } + + menu_free(menu); + return pick; +} + +// Sorts WiFi APs by RSSI (best RSSI first in the list). +static int wifi_ap_sorter(const void *a0, const void *b0) { + const wifi_ap_record_t *a = a0; + const wifi_ap_record_t *b = b0; + return b->rssi - a->rssi; +} + +void wifi_setup(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, bool scan) { + + char ssid[33] = {0}; + char username[33] = {0}; + char password[33] = {0}; + nvs_handle_t handle; + nvs_open("system", NVS_READWRITE, &handle); + bool accepted = true; + wifi_auth_mode_t authmode = WIFI_AUTH_WPA2_PSK; + esp_eap_ttls_phase2_types phase2 = ESP_EAP_TTLS_PHASE2_EAP; + + /* ==== scanning phase ==== */ + if (scan) { + // Show a little bit of text. + char *text = "Scanning..."; + pax_vec1_t dims = pax_text_size(NULL, 1, text); + float scale = pax_buffer->width / dims.x; + pax_background(pax_buffer, 0xffffffff); + pax_draw_text(pax_buffer, 0xff000000, NULL, scale, 0, (pax_buffer->height - dims.y*scale)/2, text); + ili9341_write(ili9341, pax_buffer->buf); + + // Scan for networks. + wifi_ap_record_t *aps; + size_t n_aps = wifi_scan(&aps); + + // Sort them by RSSI. + qsort(aps, n_aps, sizeof(wifi_ap_record_t), wifi_ap_sorter); + + // Make a de-duplicated list. + wifi_ap_record_t *dedup = malloc(sizeof(wifi_ap_record_t) * n_aps); + size_t n_dedup = 0; + for (size_t i = 0; i < n_aps; ) { + for (size_t x = 0; x < n_dedup; x++) { + if (!strcmp((const char *) aps[i].ssid, (const char *) dedup[x].ssid)) goto cont; + } + dedup[n_dedup] = aps[i]; + n_dedup ++; + cont: + i++; + } + + // Open a little menu for picking a network. + wifi_ap_record_t *pick = wifi_scan_results(buttonQueue, pax_buffer, ili9341, n_dedup, dedup); + if (!pick) { + nvs_close(handle); + return; + } + // Copy the SSID in. + memcpy(ssid, pick->ssid, 33); + authmode = pick->authmode; + + // Free memories. + free(aps); + free(dedup); + } else { + size_t requiredSize; + esp_err_t res = nvs_get_str(handle, "wifi.ssid", NULL, &requiredSize); + if (res != ESP_OK) { + strcpy(ssid, ""); + strcpy(password, ""); + } else if (requiredSize < sizeof(ssid)) { + res = nvs_get_str(handle, "wifi.ssid", ssid, &requiredSize); + if (res != ESP_OK) strcpy(ssid, ""); + res = nvs_get_str(handle, "wifi.password", NULL, &requiredSize); + if (res != ESP_OK) { + strcpy(password, ""); + } else if (requiredSize < sizeof(password)) { + res = nvs_get_str(handle, "wifi.password", password, &requiredSize); + if (res != ESP_OK) strcpy(password, ""); + } + } + + // Select SSID. + accepted = keyboard(buttonQueue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi SSID", "Press HOME to cancel", ssid, sizeof(ssid)); + + // Select auth mode. + if (accepted) { + authmode = wifi_auth_menu(buttonQueue, pax_buffer, ili9341, -1); + accepted = authmode != -1; + } + } + + /* ==== manual entering phase ==== */ + if (authmode == WIFI_AUTH_WPA2_ENTERPRISE) { + if (accepted) { + // Phase2 method. + phase2 = wifi_phase2_menu(buttonQueue, pax_buffer, ili9341, -1); + accepted = phase2 != -1; + } + if (accepted) { + // Username. + accepted = keyboard(buttonQueue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi username", "Press HOME to cancel", username, sizeof(username)); } } - bool accepted = keyboard(buttonQueue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi SSID", "Press HOME to exit", ssid, sizeof(ssid)); if (accepted) { - accepted = keyboard(buttonQueue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi password", "Press HOME to exit", password, sizeof(password)); + // Password. + accepted = keyboard(buttonQueue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi password", "Press HOME to cancel", password, sizeof(password)); } if (accepted) { nvs_set_str(handle, "wifi.ssid", ssid); nvs_set_str(handle, "wifi.password", password); + nvs_set_u8 (handle, "wifi.authmode", authmode); + if (authmode == WIFI_AUTH_WPA2_ENTERPRISE) { + nvs_set_str(handle, "wifi.username", username); + nvs_set_u8 (handle, "wifi.phase2", phase2); + } display_boot_screen(pax_buffer, ili9341, "WiFi settings stored"); } - nvs_set_u8(handle, "wifi.use_ent", 0); nvs_close(handle); } diff --git a/main/wifi_connect.c b/main/wifi_connect.c index 8abc613..29c20ed 100644 --- a/main/wifi_connect.c +++ b/main/wifi_connect.c @@ -21,7 +21,8 @@ bool wifi_connect_to_stored() { // Open NVS. nvs_handle_t handle; nvs_open("system", NVS_READWRITE, &handle); - uint8_t use_ent; + wifi_auth_mode_t authmode = 0; + esp_eap_ttls_phase2_types phase2 = 0; char *ssid = NULL; char *ident = NULL; char *anon_ident = NULL; @@ -36,22 +37,36 @@ bool wifi_connect_to_stored() { ssid = malloc(len); res = nvs_get_str(handle, "wifi.ssid", ssid, &len); if (res) goto errcheck; + // Check whether connection is enterprise. - res = nvs_get_u8(handle, "wifi.use_ent", &use_ent); + res = nvs_get_u8(handle, "wifi.authmode", &authmode); + bool use_ent = authmode == WIFI_AUTH_WPA2_ENTERPRISE; if (res) goto errcheck; + if (use_ent) { // Read enterprise-specific parameters. + + // Read phase2 mode. + res = nvs_get_u8(handle, "wifi.phase2", &phase2); + if (res) goto errcheck; + // Read identity. - res = nvs_get_str(handle, "wifi.ident", NULL, &len); + res = nvs_get_str(handle, "wifi.username", NULL, &len); if (res) goto errcheck; ident = malloc(len); - res = nvs_get_str(handle, "wifi.ident", ident, &len); + res = nvs_get_str(handle, "wifi.username", ident, &len); + // Read anonymous identity. res = nvs_get_str(handle, "wifi.anon_ident", NULL, &len); - if (res) goto errcheck; - anon_ident = malloc(len); - res = nvs_get_str(handle, "wifi.anon_ident", anon_ident, &len); - if (res) goto errcheck; + if (res == ESP_ERR_NVS_NOT_FOUND) { + // Default is use the same thing. + anon_ident = strdup(ident); + } else { + if (res) goto errcheck; + anon_ident = malloc(len); + res = nvs_get_str(handle, "wifi.anon_ident", anon_ident, &len); + if (res) goto errcheck; + } } // Read password. res = nvs_get_str(handle, "wifi.password", NULL, &len); @@ -65,9 +80,9 @@ bool wifi_connect_to_stored() { // Open the appropriate connection. if (use_ent) { - result = wifi_connect_ent(ssid, ident, anon_ident, password, 3); + result = wifi_connect_ent(ssid, ident, anon_ident, password, phase2, 3); } else { - result = wifi_connect(ssid, password, WIFI_AUTH_WPA2_PSK, 3); + result = wifi_connect(ssid, password, authmode, 3); } errcheck: diff --git a/main/wifi_connection.c b/main/wifi_connection.c index d607762..207069a 100644 --- a/main/wifi_connection.c +++ b/main/wifi_connection.c @@ -3,8 +3,6 @@ #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" -#include "esp_wifi.h" -#include "esp_wpa2.h" #include "esp_event.h" #include "esp_log.h" #include "lwip/err.h" @@ -113,7 +111,7 @@ bool wifi_connect(const char* aSsid, const char* aPassword, wifi_auth_mode_t aAu return false; } -bool wifi_connect_ent(const char* aSsid, const char *aIdent, const char *aAnonIdent, const char* aPassword, uint8_t aRetryMax) { +bool wifi_connect_ent(const char* aSsid, const char *aIdent, const char *aAnonIdent, const char* aPassword, esp_eap_ttls_phase2_types phase2, uint8_t aRetryMax) { retryCount = 0; maxRetries = aRetryMax; wifi_config_t wifi_config = {0}; @@ -131,7 +129,7 @@ bool wifi_connect_ent(const char* aSsid, const char *aIdent, const char *aAnonId esp_wifi_sta_wpa2_ent_set_identity((const uint8_t *) aAnonIdent, strlen(aAnonIdent)); esp_wifi_sta_wpa2_ent_set_username((const uint8_t *) aIdent, strlen(aIdent)); esp_wifi_sta_wpa2_ent_set_password((const uint8_t *) aPassword, strlen(aPassword)); - esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(ESP_EAP_TTLS_PHASE2_MSCHAPV2); + esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(phase2); // Enable enterprise auth. esp_wifi_sta_wpa2_ent_enable(); // Disable 11b as NOC asked. @@ -139,7 +137,8 @@ bool wifi_connect_ent(const char* aSsid, const char *aIdent, const char *aAnonId // Start the connection. esp_wifi_start(); - ESP_LOGI(TAG, "Connecting to WiFi..."); + ESP_LOGI(TAG, "Connecting to '%s' as '%s'/'%s': %s", aSsid, aIdent, aAnonIdent, aPassword); + ESP_LOGI(TAG, "Phase2 mode: %d", phase2); /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */