aml_commonlib: Add support for multiple networks [1/2]

PD#SWPL-163697

Problem:
The current package does not support multiple networks.

Solution:
Add support for this feature:
1.By setting priorities and then using reassociate to switch between different
networks;
2.Supports setting whether to automatically connect to other networks
when connecting to a new network fails;
3.Supports deletion of a specified network by indicating a specific id.

Verify:
ba400

Change-Id: Ib03fa6ba21b16c73b61a99e304b87b9bad761a37
Signed-off-by: yifan.li <yifan.li@amlogic.com>
diff --git a/aml_wpa_wifi_util/aml_wpa_wifi_test_demo.c b/aml_wpa_wifi_util/aml_wpa_wifi_test_demo.c
index 6c6f451..c27c5ec 100644
--- a/aml_wpa_wifi_util/aml_wpa_wifi_test_demo.c
+++ b/aml_wpa_wifi_util/aml_wpa_wifi_test_demo.c
@@ -34,13 +34,17 @@
 #include <signal.h>
 
 #include "aml_wpa_wifi_util.h"
+#include "aml_log.h"
 
 #define INVALID_INPUT -99
-#define MAX_TEST_CASE 8
+#define MAX_TEST_CASE 11
 #define INPUT_NUMBER(var, ...) get_input_string(type_int,    var, __VA_ARGS__)
 #define INPUT_STRING(var, ...) get_input_string(type_string, var, __VA_ARGS__)
 #define INPUT_CHAR(var, ...)   get_input_string(type_char,   var, __VA_ARGS__)
 
+AML_LOG_DEFINE(aml_wpa_wifi_test_demo)
+#define AML_LOG_DEFAULT AML_LOG_GET_CAT(aml_wpa_wifi_test_demo)
+
 static const char *wpa_wifi_connection_status_strings[] = {
     "WPA_WIFI_INVALID",
     "WPA_WIFI_SUCCESS",
@@ -129,13 +133,17 @@
     printf(" [ 6 ]    Get current wifi scan status      \n");
     printf(" [ 7 ]    Get current wifi connection info  \n");
     printf(" [ 8 ]    Get current connected ssid&pw     \n");
+    printf(" [ 9 ]    List the saved network id&&ssid   \n");
+    printf(" [ 10 ]   Select the network id to connect  \n");
+    printf(" [ 11 ]   Remove the network id             \n");
     printf(" [ h ]    Show this list                    \n");
     printf(" [ q ]    Quit                              \n");
     printf("***********************************************************************\n");
 }
 
 int main() {
-    wpa_wifi_init(DEFAULT_WPA_SUPL_CTRL, demo_wifi_connect_callback, 0, 1);
+    aml_log_set_from_string("all:LOG_DEBUG");
+    wpa_wifi_init(DEFAULT_WPA_SUPL_CTRL, demo_wifi_connect_callback, 1, 1);
 
     char input[16];
     char ssid[WPA_SSID_SIZE_MAX];
@@ -146,6 +154,10 @@
     int select;
     int ret;
     int is_ap_sort_by_signal_strength;
+    WPA_WIFI_NETWORK_ID_INFO network_info[MAX_NETWORKS];
+    int network_num;
+    int network_id_to_connect;
+    int network_id_to_remove;
 
     signal(SIGTERM, exit_handler);
     signal(SIGINT,  exit_handler);
@@ -219,6 +231,37 @@
                 printf("failed to get current Wi-Fi SSID and password.\n");
             }
             break;
+        case 9:
+            ret = wpa_wifi_get_networks_info(network_info, sizeof(network_info) / sizeof(network_info[0]), &network_num);
+            if (ret == RETURN_OK) {
+                printf("Number of networks: %d\n", network_num);
+                printf("Network ID\tSSID\n");
+                printf("--------------------------\n");
+                for (int i = 0; i < network_num; ++i) {
+                    printf("%d\t\t%s\n", network_info[i].network_id, network_info[i].ssid);
+                }
+            } else {
+                printf("Failed to get network information.\n");
+            }
+            break;
+        case 10:
+            INPUT_NUMBER(&network_id_to_connect, "[[ Please enter the network id to connect]] \n");
+            ret = wpa_wifi_connect_with_network_id(network_id_to_connect);
+            if (ret == RETURN_OK) {
+                printf("set network id to %d successfully\n", network_id_to_connect);
+            } else {
+                printf("failed to set network id to %d\n", network_id_to_connect);
+            }
+            break;
+        case 11:
+            INPUT_NUMBER(&network_id_to_remove, "[[ Please enter the network id to remove (-1 means remove all)]] \n");
+            ret = wpa_wifi_send_remove_network(network_id_to_remove, 1);
+            if (ret == RETURN_OK) {
+                printf("remove network id to %d successfully\n", network_id_to_remove);
+            } else {
+                printf("failed to remove network id %d\n", network_id_to_remove);
+            }
+            break;
         default:
             printf("Option [%d] not supported \n",select);
             continue;
diff --git a/aml_wpa_wifi_util/aml_wpa_wifi_util.c b/aml_wpa_wifi_util/aml_wpa_wifi_util.c
index 5e8a9f2..2382f85 100644
--- a/aml_wpa_wifi_util/aml_wpa_wifi_util.c
+++ b/aml_wpa_wifi_util/aml_wpa_wifi_util.c
@@ -79,16 +79,16 @@
             end = strchr(start, delim);                                          \
             if (!end) {                                                          \
                 break;                                                           \
-            }                                                                     \
-        }                                                                         \
+            }                                                                    \
+        }                                                                        \
         size_t length = end - start;                                             \
         if (length >= sizeof(output)) {                                          \
             break;                                                               \
-        }                                                                         \
+        }                                                                        \
         memcpy(output, start, length);                                           \
         output[length] = '\0';                                                   \
         start = end + 1;                                                         \
-        token++;                                                                  \
+        token++;                                                                 \
     }
 
     // Parse scan results
@@ -143,45 +143,6 @@
     return count;
 }
 
-static int extract_psk_from_wpa_conf(const char *filename, const char *target_ssid, char *output_psk) {
-    FILE *file = fopen(filename, "r");
-    if (file == NULL) {
-        AML_LOGE("Error opening %s file\n", filename);
-        return RETURN_ERR;
-    }
-
-    char line[MAX_LINE_LENGTH];
-    char current_ssid[WPA_SSID_SIZE_MAX];
-    char current_psk[WPA_PSK_SIZE_MAX];
-
-    output_psk[0] = '\0';
-
-    while (fgets(line, MAX_LINE_LENGTH, file) != NULL) {
-        if (strstr(line, "network={") != NULL) {
-            current_ssid[0] = '\0';
-            current_psk[0] = '\0';
-
-            while (fgets(line, MAX_LINE_LENGTH, file) != NULL) {
-                if (strstr(line, "ssid=") != NULL) {
-                    sscanf(line, " ssid=\"%[^\"]\"", current_ssid);
-                }
-                else if (strstr(line, "psk=") != NULL) {
-                    sscanf(line, " psk=\"%[^\"]\"", current_psk);
-                }
-                else if (strstr(line, "}") != NULL) {
-                    break;
-                }
-            }
-            if (strcmp(current_ssid, target_ssid) == 0) {
-                strcpy(output_psk, current_psk);
-                return RETURN_OK;
-            }
-        }
-    }
-    fclose(file);
-    return RETURN_ERR;
-}
-
 static int send_wpa_cli_command(char *reply, size_t reply_len, const char *cmd, ...) {
     char cmd_buf[WPA_SUP_CMD_MAX];
     int ret;
@@ -212,6 +173,83 @@
     return WPA_SUP_CMD_SUCCESSFUL;
 }
 
+static int wpa_wifi_get_current_connected_id(int* network_id) {
+    if (network_id == NULL) {
+        AML_LOGE("Error: NULL pointer of network_id passed.\n");
+        return RETURN_ERR;
+    }
+
+    char result[512];
+    int ret;
+    int result_len = sizeof(result) - 1;
+
+    // Get current network id
+    pthread_mutex_lock(&g_wpa_manager.sup_lock);
+    ret = send_wpa_cli_command(result, result_len, "STATUS");
+    pthread_mutex_unlock(&g_wpa_manager.sup_lock);
+    if (ret) {
+        AML_LOGE("send wpa cmd STATUS fail\n");
+        return ret;
+    }
+
+    char* cur_line = strtok(result, "\n");
+    while (cur_line != NULL) {
+        if (strncmp(cur_line, "id=", 3) == 0) {
+            *network_id = atoi(cur_line + 3);
+            AML_LOGD("Network ID found in STATUS command result, ID is %d\n", *network_id);
+            return RETURN_OK;
+        }
+        cur_line = strtok(NULL, "\n");
+    }
+
+    AML_LOGE("Network ID not found in STATUS command result.\n");
+    return RETURN_ERR;
+}
+
+static int wpa_wifi_get_current_connected_ssid(char* ssid) {
+    if (ssid == NULL) {
+        AML_LOGE("Error: NULL pointer of ssid passed.\n");
+        return RETURN_ERR;
+    }
+    int cur_network_id;
+    if (wpa_wifi_get_current_connected_id(&cur_network_id) == RETURN_OK) {
+        strcpy(ssid, g_wpa_manager.network_info[cur_network_id].ssid);
+        return RETURN_OK;
+    }
+
+    AML_LOGE("SSID not found.\n");
+    return RETURN_ERR;
+}
+
+int wpa_wifi_get_password_for_ssid(const char* ssid, char* password) {
+    FILE* conf = fopen(WPA_SUPPLICANT_CONF_PATH, "r");
+    if (!conf) {
+        AML_LOGE("Failed to open wpa_supplicant.conf.\n");
+        return RETURN_ERR;
+    }
+
+    char line[256];
+    int ssid_found = 0;
+    while (fgets(line, sizeof(line), conf) != NULL) {
+        if (strstr(line, ssid) && strstr(line, "ssid=\"")) {
+            ssid_found = 1;
+        } else if (ssid_found && strstr(line, "psk=\"")) {
+            char* psk_start = strstr(line, "psk=\"") + 5;
+            char* psk_end = strchr(psk_start, '\"');
+            if (psk_end) {
+                *psk_end = '\0';
+                strncpy(password, psk_start, psk_end - psk_start + 1);
+                fclose(conf);
+                return RETURN_OK;
+            }
+        }
+    }
+
+    fclose(conf);
+    AML_LOGE("PSK not found for SSID %s.\n", ssid);
+    return RETURN_ERR;
+}
+
 int wpa_wifi_send_scan_cmd() {
     char result[128];
     int ret;
@@ -337,25 +375,190 @@
     return ret;
 }
 
-int wpa_wifi_send_connect_cmd(const char* ssid, const char* password) {
+/*
+    When an incorrect ssid or password is entered, the thread can remove the failed connection of the network
+*/
+static void* new_connection_monitor_thread_function(void* arg) {
+
+    int timer = 0;
+    char tmp_msg[64];
+    while (!g_wpa_manager.monitor_is_stop && timer < MAX_NEW_CONNECTION_TIMEOUT)
+    {
+        if (g_wpa_manager.cur_wifi_status == WPA_WIFI_SUCCESS) {
+            break;
+        }
+        sleep(1);
+        timer++;
+        AML_LOGD("New network %d is connecting, time cost is %d seconds\n", g_wpa_manager.pending_network_id, timer);
+    }
+
+    if (timer >= MAX_NEW_CONNECTION_TIMEOUT) {
+        // This means that all networks have failed and the device is not connected to any network at this time.
+        AML_LOGD("Network [id is %d] setup failed, reason is time-out\n", g_wpa_manager.pending_network_id);
+        pthread_mutex_lock(&g_wpa_manager.sup_lock);
+        --g_wpa_manager.network_num;
+        send_wpa_cli_command(tmp_msg, sizeof(tmp_msg)-1, "SET_NETWORK %d priority %d", g_wpa_manager.previous_connected_network_id, CONNECT_NETWORK_PRIORITY);
+        if (g_wpa_manager.pending_network_id == g_wpa_manager.network_num) {
+            // Only newly added networks that do not have a successful connection will be removed.
+            send_wpa_cli_command(tmp_msg, sizeof(tmp_msg)-1, "REMOVE_NETWORK %d", g_wpa_manager.pending_network_id);
+        }
+        g_wpa_manager.pending_network_id = -1;
+        g_wpa_manager.cur_network_id = -1;
+        g_wpa_manager.previous_connected_network_id = -1;
+        g_wpa_manager.cur_wifi_status = WPA_WIFI_ERROR_UNKNOWN;
+        pthread_mutex_unlock(&g_wpa_manager.sup_lock);
+    } else {
+        // Connected to the network, but not sure if the new network is successfully connected or if automatically connected to another network,
+        // so need to determine the corresponding network id.
+        AML_LOGD("Current connected network id is %d, pending network id is %d\n", g_wpa_manager.cur_network_id, g_wpa_manager.pending_network_id);
+        pthread_mutex_lock(&g_wpa_manager.sup_lock);
+        if (g_wpa_manager.cur_network_id != g_wpa_manager.pending_network_id) {
+            --g_wpa_manager.network_num;
+            if (g_wpa_manager.cur_network_id != g_wpa_manager.previous_connected_network_id) {
+                send_wpa_cli_command(tmp_msg, sizeof(tmp_msg)-1, "SET_NETWORK %d priority %d", g_wpa_manager.previous_connected_network_id, DEFAULT_PRIORITY);
+            }
+            if (g_wpa_manager.pending_network_id == g_wpa_manager.network_num) {
+                // Only newly added networks that do not have a successful connection will be removed.
+                send_wpa_cli_command(tmp_msg, sizeof(tmp_msg)-1, "REMOVE_NETWORK %d", g_wpa_manager.pending_network_id);
+            }
+            AML_LOGD("Network [id is %d] setup failed, have re-set the last connected network [id is %d]\n", g_wpa_manager.pending_network_id, g_wpa_manager.cur_network_id);
+            g_wpa_manager.previous_connected_network_id = -1;
+            g_wpa_manager.pending_network_id = -1;
+        } else {
+            // new network is successfully set up, just set the priority of the last network
+            AML_LOGD("Network [id is %d] setup successfully\n", g_wpa_manager.cur_network_id);
+            send_wpa_cli_command(tmp_msg, sizeof(tmp_msg)-1, "SET_NETWORK %d priority %d", g_wpa_manager.previous_connected_network_id, DEFAULT_PRIORITY);
+            g_wpa_manager.previous_connected_network_id = -1;
+            g_wpa_manager.pending_network_id = -1;
+        }
+        pthread_mutex_unlock(&g_wpa_manager.sup_lock);
+    }
+    if (g_wpa_manager.save_when_connected) {
+        wpa_wifi_send_save_config_cmd();
+    }
+
+    return NULL;
+}
+
+/*
+    Connect to the specified wifi via network id
+*/
+int wpa_wifi_connect_with_network_id(int network_id) {
+    if (network_id < 0 || network_id >= g_wpa_manager.network_num) {
+        AML_LOGI("Invalid network ID: %d, current network ID count: %d\n", network_id, g_wpa_manager.network_num);
+        return RETURN_ERR;
+    }
     char result[64];
     pthread_mutex_lock(&g_wpa_manager.sup_lock);
+
     g_wpa_manager.cur_wifi_status = WPA_WIFI_INVALID;
-    send_wpa_cli_command(result, sizeof(result)-1, "REMOVE_NETWORK %d", g_wpa_manager.cur_enable_network_id);
+
+    g_wpa_manager.previous_connected_network_id = g_wpa_manager.cur_network_id;
+    g_wpa_manager.pending_network_id = network_id;
+    if (g_wpa_manager.auto_connect_when_fail) {
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d priority %d", g_wpa_manager.previous_connected_network_id, LAST_CONNECT_PRIORITY);
+        send_wpa_cli_command(result, sizeof(result)-1, "ENABLE_NETWORK all");
+    } else {
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d priority %d", g_wpa_manager.previous_connected_network_id, DEFAULT_PRIORITY);
+        send_wpa_cli_command(result, sizeof(result)-1, "DISABLE_NETWORK all");
+    }
+
+    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d priority %d", g_wpa_manager.pending_network_id, CONNECT_NETWORK_PRIORITY);
+    send_wpa_cli_command(result, sizeof(result)-1, "ENABLE_NETWORK %d", g_wpa_manager.pending_network_id);
+    send_wpa_cli_command(result, sizeof(result)-1, "REASSOCIATE");
+    pthread_mutex_unlock(&g_wpa_manager.sup_lock);
+
+    // Start a thread to monitor new connection
+    pthread_t new_connection_monitor_thread;
+    pthread_create(&new_connection_monitor_thread, NULL, new_connection_monitor_thread_function, NULL);
+
+    return RETURN_OK;
+}
+
+int wpa_wifi_send_connect_cmd(const char* ssid, const char* password) {
+    char result[64];
+    int network_id;
+    pthread_mutex_lock(&g_wpa_manager.sup_lock);
+
     send_wpa_cli_command(result, sizeof(result)-1, "ADD_NETWORK");
+    network_id = atoi(result);
+    g_wpa_manager.network_num++;
+    g_wpa_manager.network_info[network_id].network_id = network_id;
+    strcpy(g_wpa_manager.network_info[network_id].ssid, ssid);
+    AML_LOGI("Added new network with network ID: %d\n", network_id);
 
     // set ssid
-    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d ssid \"%s\"", g_wpa_manager.cur_enable_network_id, ssid);
-    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d key_mgmt WPA-PSK", g_wpa_manager.cur_enable_network_id);
+    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d ssid \"%s\"", network_id, ssid);
+    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d key_mgmt WPA-PSK", network_id);
     // set psk
-    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d psk \"%s\"", g_wpa_manager.cur_enable_network_id, password);
+    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d psk \"%s\"", network_id, password);
 
-    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d pairwise CCMP TKIP", g_wpa_manager.cur_enable_network_id);
-    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d group CCMP TKIP", g_wpa_manager.cur_enable_network_id);
-    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d proto RSN", g_wpa_manager.cur_enable_network_id);
+    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d pairwise CCMP TKIP", network_id);
+    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d group CCMP TKIP", network_id);
+    send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d proto RSN", network_id);
 
-    send_wpa_cli_command(result, sizeof(result)-1, "ENABLE_NETWORK %d", g_wpa_manager.cur_enable_network_id);
-    send_wpa_cli_command(result, sizeof(result)-1, "REASSOCIATE");
+    pthread_mutex_unlock(&g_wpa_manager.sup_lock);
+
+    wpa_wifi_connect_with_network_id(network_id);
+
+    return RETURN_OK;
+}
+
+int wpa_wifi_send_remove_network(int network_id, int is_save_config) {
+    if (network_id < -1 || network_id >= g_wpa_manager.network_num) {
+        AML_LOGI("Invalid network ID: %d, current network ID count: %d\n", network_id, g_wpa_manager.network_num);
+        return RETURN_ERR;
+    }
+    char result[64];
+    pthread_mutex_lock(&g_wpa_manager.sup_lock);
+    // -1 means all
+    if (-1 == network_id) {
+        g_wpa_manager.network_num = 0;
+        send_wpa_cli_command(result, sizeof(result)-1, "REMOVE_NETWORK all");
+    } else if (g_wpa_manager.network_num - 1 == network_id) {
+        send_wpa_cli_command(result, sizeof(result)-1, "REMOVE_NETWORK %d", network_id);
+        --g_wpa_manager.network_num;
+    } else {
+        // Because when wpa_supplicant add_network only supports +1 on the largest id, so if remove_network is not the largest id,
+        // there will be free ids that are not being used, so the swap is applied
+        char value[64];
+        char password[64];
+        int max_network_id = g_wpa_manager.network_num - 1;
+        send_wpa_cli_command(value, sizeof(value)-1, "GET_NETWORK %d ssid", max_network_id);
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d ssid %s", network_id, value);
+
+        wpa_wifi_get_password_for_ssid(value, password);
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d psk \"%s\"", network_id, password);
+
+        send_wpa_cli_command(value, sizeof(value)-1, "GET_NETWORK %d key_mgmt", max_network_id);
+
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d key_mgmt %s", network_id, value);
+
+        send_wpa_cli_command(value, sizeof(value)-1, "GET_NETWORK %d pairwise", max_network_id);
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d pairwise %s", network_id, value);
+
+        send_wpa_cli_command(value, sizeof(value)-1, "GET_NETWORK %d group", max_network_id);
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d group %s", network_id, value);
+
+        send_wpa_cli_command(value, sizeof(value)-1, "GET_NETWORK %d proto", max_network_id);
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d proto %s", network_id, value);
+
+        send_wpa_cli_command(value, sizeof(value)-1, "GET_NETWORK %d priority", max_network_id);
+        send_wpa_cli_command(result, sizeof(result)-1, "SET_NETWORK %d priority %s", network_id, value);
+
+        send_wpa_cli_command(result, sizeof(result)-1, "REMOVE_NETWORK %d", max_network_id);
+
+        strcpy(g_wpa_manager.network_info[network_id].ssid, g_wpa_manager.network_info[max_network_id].ssid);
+        --g_wpa_manager.network_num;
+
+        if (g_wpa_manager.cur_network_id == max_network_id || g_wpa_manager.cur_network_id == network_id)
+            send_wpa_cli_command(result, sizeof(result)-1, "REASSOCIATE");
+    }
+
+    if (is_save_config) {
+        send_wpa_cli_command(result, sizeof(result)-1, "SAVE_CONFIG");
+    }
+
     pthread_mutex_unlock(&g_wpa_manager.sup_lock);
 
     return RETURN_OK;
@@ -378,7 +581,7 @@
             if (0 == wpa_ctrl_recv(g_wpa_manager.ctrl_handle, event_buf, &event_buf_len)) {
                 start = strchr(event_buf, '>') + 1;
                 if (start == NULL) continue;
-                AML_LOGI("Received event (length = %d) message: %s\n", (int)event_buf_len, start);
+                // AML_LOGD("Received event (length = %d) message: %s\n", (int)event_buf_len, start);
 
                 if (strstr(start, WPA_EVENT_SCAN_STARTED) != NULL) {
                     AML_LOGI("Scanning started \n");
@@ -388,7 +591,7 @@
                     if (g_wpa_manager.cur_scan_status == WPA_WIFI_SCAN_STATE_CMD_SENT) {
                         /* Flush the BSS everytime so that there is no stale information */
                         AML_LOGI("Flushing the BSS now\n");
-                        send_wpa_cli_command(result_buf, sizeof(result_buf)-1, "BSS_FLUSH %d", g_wpa_manager.cur_enable_network_id);
+                        send_wpa_cli_command(result_buf, sizeof(result_buf)-1, "BSS_FLUSH %d", g_wpa_manager.cur_network_id);
                         g_wpa_manager.cur_scan_status = WPA_WIFI_SCAN_STATE_STARTED;
                     }
                     pthread_mutex_unlock(&g_wpa_manager.sup_lock);
@@ -409,57 +612,40 @@
                 }
                 else if (strstr(start, WPS_EVENT_TIMEOUT) != NULL) {
                     AML_LOGI("WPS Connection is timeout\n");
-                    char cur_ssid[WPA_SSID_SIZE_MAX];
                     pthread_mutex_lock(&g_wpa_manager.sup_lock);
-                    // get ssid
-                    send_wpa_cli_command(cur_ssid, sizeof(cur_ssid)-1,"GET_NETWORK %d ssid", g_wpa_manager.cur_enable_network_id);
                     g_wpa_manager.cur_wifi_status = WPA_WIFI_ERROR_NOT_FOUND;
                     pthread_mutex_unlock(&g_wpa_manager.sup_lock);
-                    if (g_wpa_manager.connect_callback) {
-                        g_wpa_manager.connect_callback(cur_ssid, &g_wpa_manager.cur_wifi_status);
-                    }
                 }
                 else if (strstr(start, WPS_EVENT_SUCCESS) != NULL) {
                     AML_LOGI("WPS is successful...Associating now\n");
                 }
                 else if (strstr(start, WPA_EVENT_CONNECTED) != NULL) {
                     AML_LOGI("Authentication completed successfully and data connection enabled\n");
-                    char cur_ssid[WPA_SSID_SIZE_MAX];
+                    // get current connected network id
+                    wpa_wifi_get_current_connected_id(&g_wpa_manager.cur_network_id);
+                    AML_LOGD("Current ssid is %s\n", g_wpa_manager.network_info[g_wpa_manager.cur_network_id].ssid);
                     pthread_mutex_lock(&g_wpa_manager.sup_lock);
-                    // get ssid
-                    send_wpa_cli_command(cur_ssid, sizeof(cur_ssid)-1,"GET_NETWORK %d ssid", g_wpa_manager.cur_enable_network_id);
-                    if (strcmp(g_wpa_manager.cur_connected_ssid, cur_ssid) != 0) {
-                        // mean new ssid connection
-                        strcpy(g_wpa_manager.cur_connected_ssid, cur_ssid);
-                        AML_LOGD("Update the current connected ssid to %s\n", cur_ssid);
-                    }
                     g_wpa_manager.cur_wifi_status = WPA_WIFI_SUCCESS;
-
+                    send_wpa_cli_command(result_buf, sizeof(result_buf)-1, "SET_NETWORK %d priority %d", g_wpa_manager.cur_network_id, CONNECT_NETWORK_PRIORITY);
                     if (g_wpa_manager.save_when_connected) {
                         send_wpa_cli_command(result_buf, sizeof(result_buf)-1,"SAVE_CONFIG");
                     }
                     pthread_mutex_unlock(&g_wpa_manager.sup_lock);
                     if (g_wpa_manager.connect_callback) {
-                        g_wpa_manager.connect_callback(cur_ssid, &g_wpa_manager.cur_wifi_status);
+                        g_wpa_manager.connect_callback(g_wpa_manager.network_info[g_wpa_manager.cur_network_id].ssid, &g_wpa_manager.cur_wifi_status);
                     }
                 }
                 else if (strstr(start, WPA_EVENT_DISCONNECTED) != NULL) {
-                    char cur_ssid[WPA_SSID_SIZE_MAX];
                     pthread_mutex_lock(&g_wpa_manager.sup_lock);
-                    // get ssid
-                    send_wpa_cli_command(cur_ssid, sizeof(cur_ssid)-1,"GET_NETWORK %d ssid", g_wpa_manager.cur_enable_network_id);
                     g_wpa_manager.cur_wifi_status = WPA_WIFI_DISCONNECTED;
                     pthread_mutex_unlock(&g_wpa_manager.sup_lock);
-                    AML_LOGI("Disconnected from the network:%s\n", cur_ssid);
-                    if (g_wpa_manager.connect_callback) {
-                        g_wpa_manager.connect_callback(cur_ssid, &g_wpa_manager.cur_wifi_status);
-                    }
+                    AML_LOGI("Disconnected from the network\n");
                 }
-                else if (strstr(start, WPA_EVENT_TEMP_DISABLED) != NULL){
+                else if (strstr(start, WPA_EVENT_TEMP_DISABLED) != NULL) {
                     char cur_ssid[WPA_SSID_SIZE_MAX];
                     pthread_mutex_lock(&g_wpa_manager.sup_lock);
                     // get ssid
-                    send_wpa_cli_command(cur_ssid, sizeof(cur_ssid)-1,"GET_NETWORK %d ssid", g_wpa_manager.cur_enable_network_id);
+                    send_wpa_cli_command(cur_ssid, sizeof(cur_ssid)-1,"GET_NETWORK %d ssid", g_wpa_manager.cur_network_id);
 
                     AML_LOGI("Network authentication failure (Incorrect password), ssid is %s\n", cur_ssid);
 
@@ -470,18 +656,10 @@
                     }
                 }
                 else if (strstr(start, WPA_EVENT_NETWORK_NOT_FOUND) != NULL) {
-                    char cur_ssid[WPA_SSID_SIZE_MAX];
                     pthread_mutex_lock(&g_wpa_manager.sup_lock);
-                    // get ssid
-                    send_wpa_cli_command(cur_ssid, sizeof(cur_ssid)-1,"GET_NETWORK %d ssid", g_wpa_manager.cur_enable_network_id);
-
-                    AML_LOGI("Received a network not found event, ssid is %s\n", cur_ssid);
-
+                    AML_LOGI("Received a network not found event\n");
                     g_wpa_manager.cur_wifi_status = WPA_WIFI_ERROR_NOT_FOUND;
                     pthread_mutex_unlock(&g_wpa_manager.sup_lock);
-                    if (g_wpa_manager.connect_callback) {
-                        g_wpa_manager.connect_callback(cur_ssid, &g_wpa_manager.cur_wifi_status);
-                    }
                 }
                 else {
                     continue;
@@ -577,102 +755,126 @@
         AML_LOGE("Error: NULL pointer of ssid or password passed.\n");
         return RETURN_ERR;
     }
-    char result[512];
-    int ret;
-    int result_len = sizeof(result)-1;
 
-    // Get current ssid
-    if (g_wpa_manager.cur_wifi_status != WPA_WIFI_SUCCESS) {
-        AML_LOGW("Current wifi is unconnected \n");
-        return RETURN_ERR;
-    }
-    pthread_mutex_lock(&g_wpa_manager.sup_lock);
-    ret = send_wpa_cli_command(result, result_len, "STATUS");
-    pthread_mutex_unlock(&g_wpa_manager.sup_lock);
-    if (ret) {
-        AML_LOGE("send wpa cmd STATUS fail\n");
-        return ret;
-    }
-    char* cur_line = strtok(result, "\n");
-    while (cur_line != NULL) {
-        if (strncmp(cur_line, "ssid=", 5) == 0) {
-            char* ssid_start = cur_line + 5;
-            char* ssid_end = strchr(ssid_start, '\0');
-            if (ssid_end) {
-                *ssid_end = '\0'; // Null-terminate the SSID string
-                strncpy(ssid, ssid_start, ssid_end - ssid_start + 1);
-                break;
-            } else {
-                AML_LOGE("SSID not found in STATUS command result.\n");
-                return RETURN_ERR;
-            }
-        }
-        cur_line = strtok(NULL, "\n");
-    }
-
-    if (cur_line == NULL) {
-        AML_LOGE("SSID not found in STATUS command result.\n");
+    // Get current SSID
+    if (wpa_wifi_get_current_connected_ssid(ssid) != RETURN_OK) {
         return RETURN_ERR;
     }
 
-    // Read the wpa_supplicant.conf file to find the PSK for the current SSID
-    FILE* conf = fopen(WPA_SUPPLICANT_CONF_PATH, "r");
-    if (!conf) {
-        AML_LOGE("Failed to open wpa_supplicant.conf.\n");
+    // Get password for the current SSID
+    if (wpa_wifi_get_password_for_ssid(ssid, password) != RETURN_OK) {
         return RETURN_ERR;
     }
 
-    char line[256];
-    int ssid_found = 0;
-    while (fgets(line, sizeof(line), conf) != NULL) {
-        if (strstr(line, ssid) && strstr(line, "ssid=\"")) {
-            ssid_found = 1;
-        } else if (ssid_found && strstr(line, "psk=\"")) {
-            char* psk_start = strstr(line, "psk=\"") + 5;
-            char* psk_end = strchr(psk_start, '\"');
-            if (psk_end) {
-                *psk_end = '\0';
-                strncpy(password, psk_start, psk_end - psk_start + 1);
-                fclose(conf);
-                return RETURN_OK;
-            }
+    return RETURN_OK;
+}
+
+int wpa_wifi_get_networks_info(WPA_WIFI_NETWORK_ID_INFO network_info[], const int array_size, int* network_num) {
+    if (network_info == NULL || network_num == NULL) {
+        return RETURN_ERR;
+    }
+    if (g_wpa_manager.network_num <= 0 || g_wpa_manager.network_info == NULL) {
+        *network_num = 0;
+        return RETURN_OK;
+    }
+    int copy_num = (g_wpa_manager.network_num < array_size) ? g_wpa_manager.network_num : array_size;
+
+    for (int i = 0; i < copy_num; ++i) {
+        network_info[i].network_id = g_wpa_manager.network_info[i].network_id;
+        strncpy(network_info[i].ssid, g_wpa_manager.network_info[i].ssid, sizeof(network_info[i].ssid));
+    }
+
+    *network_num = copy_num;
+    return RETURN_OK;
+}
+
+/*
+    Determine if the input ssid has been saved in the configuration,
+    if yes, get the corresponding network id;
+*/
+int wpa_wifi_ssid_is_saved_in_config(const char* ssid, int* network_id) {
+    if (!ssid || !network_id) return 0;
+    for (int i = 0; i < g_wpa_manager.network_num; i++) {
+        if (strcmp(g_wpa_manager.network_info[i].ssid, ssid) == 0) {
+            *network_id = g_wpa_manager.network_info[i].network_id;
+            return 1;
         }
     }
-
-    fclose(conf);
-    AML_LOGE("PSK not found for SSID %s.\n", ssid);
-    return RETURN_ERR;
-
+    return 0;
 }
 
 /*
     Mainly to make sure to get the status of connected, when the wifi is already connected;
     the other statuses don't matter
 */
-static int init_cur_wifi_status() {
+static void init_cur_wifi_status() {
     char result[512];
     int ret;
     pthread_mutex_lock(&g_wpa_manager.sup_lock);
     ret = send_wpa_cli_command(result, sizeof(result)-1, "STATUS");
     pthread_mutex_unlock(&g_wpa_manager.sup_lock);
     if (!ret) {
-        AML_LOGI("get wpa wifi STATUS successfully, scurrent status is :\n %s\n", result);
-        if (strstr(result, "wpa_state=COMPLETED") != NULL) {
-            g_wpa_manager.cur_wifi_status = WPA_WIFI_SUCCESS;
+        AML_LOGI("get wpa wifi STATUS successfully, current status is:\n%s\n", result);
+
+        char *pos = result;
+        char *token;
+        while ((token = strtok_r(pos, "\n", &pos)) != NULL) {
+            if (strstr(token, "wpa_state=COMPLETED") != NULL) {
+                g_wpa_manager.cur_wifi_status = WPA_WIFI_SUCCESS;
+            } else if (strstr(token, "id=") != NULL) {
+                sscanf(token, "id=%d", &g_wpa_manager.cur_network_id);
+            }
         }
+
+        AML_LOGI("Connection Status: %s\n", (g_wpa_manager.cur_wifi_status == WPA_WIFI_SUCCESS) ? "Connected" : "Disconnected");
+        AML_LOGI("Current Network ID: %d\n", g_wpa_manager.cur_network_id);
     } else {
-        AML_LOGE("get wpa wifi STATUS fail\n");
+        AML_LOGE("Get wpa wifi STATUS fail\n");
     }
-    return ret;
 }
 
-int wpa_wifi_init (const char* wpa_supl_ctrl, wpa_wifi_connect_callback connect_callback, int enable_network_id, int save_when_connected) {
+/*
+    Load content locally from list_networks, include network id and ssid
+*/
+static void init_network_info() {
+    char result[512];
+    int ret;
+    int num_networks = 0;
+    pthread_mutex_lock(&g_wpa_manager.sup_lock);
+    ret = send_wpa_cli_command(result, sizeof(result)-1, "LIST_NETWORKS");
+    pthread_mutex_unlock(&g_wpa_manager.sup_lock);
+    if (!ret) {
+        char *pos = result;
+        char *token;
+        while ((token = strtok_r(pos, "\n", &pos)) != NULL) {
+            if (strstr(token, "network id") != NULL || strstr(token, "---") != NULL) {
+                continue;
+            }
+            int network_id;
+            char ssid[WPA_SSID_SIZE_MAX];
+            if (sscanf(token, "%d\t%[^\t\n]", &network_id, ssid) == 2 && num_networks < MAX_NETWORKS) {
+                g_wpa_manager.network_info[num_networks].network_id = network_id;
+                strcpy(g_wpa_manager.network_info[num_networks].ssid, ssid);
+                num_networks++;
+            }
+        }
+        g_wpa_manager.network_num = num_networks;
+        AML_LOGI("Number of networks: %d\n", g_wpa_manager.network_num);
+    } else {
+        AML_LOGE("Failed to get network list\n");
+    }
+}
+
+int wpa_wifi_init(const char* wpa_supl_ctrl, wpa_wifi_connect_callback connect_callback, int save_when_connected, int auto_connect_when_fail) {
     int retry = 0;
     g_wpa_manager.connect_callback = connect_callback;
-    g_wpa_manager.cur_enable_network_id = enable_network_id;
     g_wpa_manager.save_when_connected = save_when_connected;
+    g_wpa_manager.auto_connect_when_fail = auto_connect_when_fail;
+    g_wpa_manager.cur_network_id = -1;
+    g_wpa_manager.network_num = 0;
+    g_wpa_manager.previous_connected_network_id = -1;
+    g_wpa_manager.pending_network_id = -1;
     g_wpa_manager.monitor_is_stop = 0;
-    g_wpa_manager.cur_connected_ssid[0] = '\0';
     g_wpa_manager.ctrl_handle = wpa_ctrl_open(wpa_supl_ctrl);
 
     while (g_wpa_manager.ctrl_handle == NULL) {
@@ -687,10 +889,7 @@
     }
 
     init_cur_wifi_status();
-    // get current ssid
-    pthread_mutex_lock(&g_wpa_manager.sup_lock);
-    send_wpa_cli_command(g_wpa_manager.cur_connected_ssid, sizeof(g_wpa_manager.cur_connected_ssid)-1,"GET_NETWORK %d ssid", g_wpa_manager.cur_enable_network_id);
-    pthread_mutex_unlock(&g_wpa_manager.sup_lock);
+    init_network_info();
 
     if (wpa_ctrl_attach(g_wpa_manager.ctrl_handle) != 0) {
         AML_LOGE("wpa_ctrl_attach failed \n");
diff --git a/aml_wpa_wifi_util/aml_wpa_wifi_util.h b/aml_wpa_wifi_util/aml_wpa_wifi_util.h
index 6e5f447..05bd691 100644
--- a/aml_wpa_wifi_util/aml_wpa_wifi_util.h
+++ b/aml_wpa_wifi_util/aml_wpa_wifi_util.h
@@ -46,18 +46,24 @@
     Return values for WPA Supplicant command execution
 */
 #define WPA_SUP_CMD_SUCCESSFUL 0
-#define WPA_SUP_CMD_FAILED -1 // Return value in case WPA command failed
-#define WPA_SUP_CMD_TIMEOUT -2 // Return value in case WPA command timed out
-#define WPA_SUP_CMD_INIT_ERR -3 // Return value in case wifi_init is not done
+#define WPA_SUP_CMD_FAILED -1               // Return value in case WPA command failed
+#define WPA_SUP_CMD_TIMEOUT -2              // Return value in case WPA command timed out
+#define WPA_SUP_CMD_INIT_ERR -3             // Return value in case wifi_init is not done
 
-#define WPA_SUP_TIMEOUT 500000 // 500 msec
-#define WPA_SUP_CMD_MAX 256 // Maximum command size that can be sent to WPA Supplicant
-#define WPA_SSID_SIZE_MAX 64 // Maximum SSID length
-#define WPA_BSSID_SIZE_MAX 64 // Maximum BSSID length
-#define WPA_PSK_SIZE_MAX 64 // Maximum PSK length
-#define WPA_AP_NUM_MAX 64 // Maximum number of scanned APs to store
+#define WPA_SUP_TIMEOUT 500000              // 500 msec
+#define WPA_SUP_CMD_MAX 256                 // Maximum command size that can be sent to WPA Supplicant
+#define WPA_SSID_SIZE_MAX 64                // Maximum SSID length
+#define WPA_BSSID_SIZE_MAX 64               // Maximum BSSID length
+#define WPA_PSK_SIZE_MAX 64                 // Maximum PSK length
+#define WPA_AP_NUM_MAX 64                   // Maximum number of scanned APs to store
 
+#define DEFAULT_PRIORITY 0                  // Priority of the default network
+#define LAST_CONNECT_PRIORITY 98            // Priority of the network after failed connection, that is the previous network id
+#define CONNECT_NETWORK_PRIORITY 99         // Priority of the network to be connected
+
+#define MAX_NEW_CONNECTION_TIMEOUT 24       // Maximum timeout for new network connection (in seconds)
 #define MAX_RETRY 10
+#define MAX_NETWORKS 10                     // Maximum number of networks that can be saved to the configuration
 
 /*
     Wi-Fi status types
@@ -84,29 +90,49 @@
     WPA_WIFI_SCAN_STATE_RESULTS_RECEIVED,
 } WPA_WIFI_SCAN_STATE;
 
+/*
+    Wi-Fi network id info
+*/
+typedef struct {
+    int network_id;
+    char ssid[WPA_SSID_SIZE_MAX];
+} WPA_WIFI_NETWORK_ID_INFO;
+
 typedef void(* wpa_wifi_connect_callback) (char *ssid, const WPA_WIFI_STATUS_TYPE *cur_status);
 
 typedef struct {
+    // Pointer to the control handle for communication with WPA Supplicant
     struct wpa_ctrl *ctrl_handle;
 
     // Callback function for Wi-Fi connection events
     wpa_wifi_connect_callback connect_callback;
 
+    // Flag indicating whether the monitoring thread is stopped
     int monitor_is_stop;
+    // Thread ID of the monitoring thread
     pthread_t monitor_thread_id;
 
-    // scan state and wifi connect status
+    // Scan state and wifi connect status
     WPA_WIFI_SCAN_STATE cur_scan_status;
     WPA_WIFI_STATUS_TYPE cur_wifi_status;
 
+    // Mutex lock to protect shared resources
     pthread_mutex_t sup_lock;
 
-    // Whether we want to save SSID information to configuration file: 1=save, 0=don't save
-    int cur_enable_network_id;
+    // Whether we want to save network information to configuration file: 1=save, 0=don't save
     int save_when_connected;
 
-    char cur_connected_ssid[WPA_SSID_SIZE_MAX];
-}WPA_WIFI_MANAGER;
+    // Info of network
+    int network_num;                                            // Numbers of networks
+    int cur_network_id;                                         // ID of the current connected network
+    int previous_connected_network_id;                          // ID of the previously connected network
+    int pending_network_id;                                     // ID of the pending network
+    WPA_WIFI_NETWORK_ID_INFO network_info[MAX_NETWORKS];        // Array to store network information
+
+    // Flag indicating whether to automatically connect to another network when connection fails
+    int auto_connect_when_fail;
+
+} WPA_WIFI_MANAGER;
 
 typedef enum {
     WPA_WIFI_LEVEL_0,  // rssi <= -100
@@ -117,12 +143,12 @@
 } WPA_WIFI_SIGNAL_LEVEL;
 
 typedef struct {
-    char bssid[WPA_BSSID_SIZE_MAX];  // BSSID
-    int frequency;   // Frequency
-    int signal_strength; // Signal Strength
-    WPA_WIFI_SIGNAL_LEVEL signal_level; // Signal Level
-    char flags[256];  // Flags
-    char ssid[WPA_SSID_SIZE_MAX];    // SSID
+    char bssid[WPA_BSSID_SIZE_MAX];             // BSSID
+    int frequency;                              // Frequency
+    int signal_strength;                        // Signal Strength
+    WPA_WIFI_SIGNAL_LEVEL signal_level;         // Signal Level
+    char flags[256];                            // Flags
+    char ssid[WPA_SSID_SIZE_MAX];               // SSID
 } WPA_WIFI_AP_INFO;
 
 int wpa_wifi_send_scan_cmd();
@@ -137,13 +163,19 @@
 int wpa_wifi_send_connect_cmd(const char* ssid, const char* password);
 int wpa_wifi_send_disconnect_cmd();
 int wpa_wifi_send_reconnect_cmd();
+int wpa_wifi_send_remove_network(int network_id, int is_save_config);
 
 int wpa_wifi_get_current_wifi_status(WPA_WIFI_STATUS_TYPE* status);
 int wpa_wifi_get_current_scan_status(WPA_WIFI_SCAN_STATE* status);
 int wpa_wifi_get_scan_results(WPA_WIFI_AP_INFO wifi_array_to_fill[], const int array_size, int* ap_count, int is_sort_by_strength);
 int wpa_wifi_get_current_connected_ssid_and_password(char* ssid, char* password);
+int wpa_wifi_get_password_for_ssid(const char* ssid, char* password);
+int wpa_wifi_get_networks_info(WPA_WIFI_NETWORK_ID_INFO network_info[], const int array_size, int* network_num);
 
-int wpa_wifi_init(const char* wpa_supl_ctrl, wpa_wifi_connect_callback connect_callback, int enable_network_id, int save_when_connected);
+int wpa_wifi_ssid_is_saved_in_config(const char* ssid, int* network_id);
+int wpa_wifi_connect_with_network_id(const int network_id);
+
+int wpa_wifi_init(const char* wpa_supl_ctrl, wpa_wifi_connect_callback connect_callback, int save_when_connected, int auto_connect_when_fail);
 int wpa_wifi_uninit();
 
 #ifdef __cplusplus