Merge "[rdk-b][mt7986][wifi-hal][Add ApSecurity related functions]"
diff --git a/src/wifi/wifi_hal.c b/src/wifi/wifi_hal.c
index b24d391..bbdc0b5 100644
--- a/src/wifi/wifi_hal.c
+++ b/src/wifi/wifi_hal.c
@@ -77,6 +77,10 @@
 #define GUARD_INTERVAL_FILE "/tmp/guard-interval"
 #define CHANNEL_STATS_FILE "/tmp/channel_stats"
 #define DFS_ENABLE_FILE "/nvram/dfs_enable.txt"
+#define VLAN_FILE "/nvram/hostapd.vlan"
+#define PSK_FILE "/tmp/hostapd"
+#define CHAIN_MASK_FILE "/tmp/chain_mask"
+#define AMSDU_FILE "/tmp/AMSDU"
 
 #define DRIVER_2GHZ "ath9k"
 #define DRIVER_5GHZ "ath10k_pci"
@@ -197,6 +201,7 @@
 wifi_secur_list *       wifi_get_item_by_key(wifi_secur_list *list, int list_sz, int key);
 wifi_secur_list *       wifi_get_item_by_str(wifi_secur_list *list, int list_sz, const char *str);
 char *                  wifi_get_str_by_key(wifi_secur_list *list, int list_sz, int key);
+static int ieee80211_channel_to_frequency(int channel, int *freqMHz);
 
 static wifi_secur_list map_security[] =
 {
@@ -3510,19 +3515,18 @@
     char buf[128]={0};
     char file_name[32] = {0};
     char filter_SSID[32] = {0};
+    char line[256] = {0};
+    char *ret = NULL;
     int freq=0;
     FILE *f = NULL;
     size_t len=0;
-    ssize_t read = 0;
-    char *line =NULL;
-    // int noise_arr[channels_num] = {0};
     int channels_num = 0;
     int vht_channel_width = 0;
     bool get_nosie_ret = false;
     bool filter_enable = false;
     bool filter_BSS = false;     // The flag determine whether the BSS information need to be filterd.
 
-    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s: %d\n", __func__, __LINE__);
 
     snprintf(file_name, sizeof(file_name), "%s%d.txt", ESSID_FILE, radioIndex);
     f = fopen(file_name, "r");
@@ -3535,20 +3539,20 @@
 
     snprintf(cmd, sizeof(cmd), "iw phy phy%d channels | grep * | grep -v disable | wc -l", radioIndex);
     _syscmd(cmd, buf, sizeof(buf));
-    channels_num = atoi(buf);
+    channels_num = strtol(buf, NULL, 10);
 
     struct channels_noise *channels_noise_arr = calloc(channels_num, sizeof(struct channels_noise));
     get_nosie_ret = get_noise(radioIndex, channels_noise_arr, channels_num);
 
     sprintf(cmd, "iw dev %s%d scan | grep '%s%d\\|SSID\\|freq\\|beacon interval\\|capabilities\\|signal\\|Supported rates\\|DTIM\\| \
-    // WPA\\|RSN\\|Group cipher\\|HT operation\\|secondary channel offset\\|channel width\\|HE160' | grep -v -e '*.*BSS'", AP_PREFIX, radioIndex, AP_PREFIX, radioIndex);
+    // WPA\\|RSN\\|Group cipher\\|HT operation\\|secondary channel offset\\|channel width\\|HE.*GHz' | grep -v -e '*.*BSS'", AP_PREFIX, radioIndex, AP_PREFIX, radioIndex);
     fprintf(stderr, "cmd: %s\n", cmd);
     if ((f = popen(cmd, "r")) == NULL) {
         wifi_dbg_printf("%s: popen %s error\n", __func__, cmd);
         return RETURN_ERR;
     }
-    line = malloc(sizeof(char) * 256);
-    while ((read = getline(&line, &len, f)) != -1) {
+    ret = fgets(line, sizeof(line), f);
+    while (ret != NULL) {
         if(strstr(line, "BSS") != NULL) {    // new neighbor info
             // The SSID field is not in the first field. So, we should store whole BSS informations and the filter flag. 
             // And we will determine whether we need the previous BSS infomation when parsing the next BSS field or end of while loop.
@@ -3635,7 +3639,7 @@
             strcat(scan_array[index].ap_SupportedStandards, ",n");
             strcpy(scan_array[index].ap_OperatingStandards, "n");
         } else if (strstr(line, "VHT operation") != NULL) {
-            read = getline(&line, &len, f);
+            ret = fgets(line, sizeof(line), f);
             sscanf(line,"		 * channel width: %d", &vht_channel_width);
             if(vht_channel_width == 1) {
                 snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11AC_VHT80");
@@ -3645,7 +3649,7 @@
             if (strstr(line, "BSS") != NULL)   // prevent to get the next neighbor information
                 continue;
         } else if (strstr(line, "HT operation") != NULL) {
-            read = getline(&line, &len, f);
+            ret = fgets(line, sizeof(line), f);
             sscanf(line,"		 * secondary channel offset: %s", &buf);
             if (!strcmp(buf, "above")) {
                 //40Mhz +
@@ -3661,22 +3665,24 @@
             if (strstr(line, "BSS") != NULL)   // prevent to get the next neighbor information
                 continue;
         } else if (strstr(line, "HE capabilities") != NULL) {
-            strncat(scan_array[index].ap_SupportedStandards, ",ax", strlen(",ax"));
-            strncpy(scan_array[index].ap_OperatingStandards, "ax", strlen("ax"));
-        } else if (strstr(line, "HE PHY Capabilities") != NULL) {
+            strcat(scan_array[index].ap_SupportedStandards, ",ax");
+            strcpy(scan_array[index].ap_OperatingStandards, "ax");
+            ret = fgets(line, sizeof(line), f);
             if (strncmp(scan_array[index].ap_OperatingFrequencyBand, "2.4GHz", strlen("2.4GHz")) == 0) {
                 if (strstr(line, "HE40/2.4GHz") != NULL)
-                    strncpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE40PLUS", strlen("11AXHE40PLUS"));
+                    strcpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE40PLUS");
                 else
-                    strncpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE20", strlen("11AXHE20"));
+                    strcpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE20");
             } else if (strncmp(scan_array[index].ap_OperatingFrequencyBand, "5GHz", strlen("5GHz")) == 0) {
-                strncpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE80", strlen("11AXHE80"));    // AP must always support
-                read = getline(&line, &len, f);
+                if (strstr(line, "HE80/5GHz") != NULL) {
+                    strcpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE80");
+                    ret = fgets(line, sizeof(line), f);
+                } else
+                    continue;
                 if (strstr(line, "HE160/5GHz") != NULL)
-                    strncpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE160", strlen("11AXHE160"));
+                    strcpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE160");
             }
-            if (strstr(line, "BSS") != NULL)   // prevent to get the next neighbor information
-                continue;
+            continue;
         } else if (strstr(line, "WPA") != NULL) {
             strcpy(scan_array[index].ap_SecurityModeEnabled, "WPA");
         } else if (strstr(line, "RSN") != NULL) {
@@ -3687,6 +3693,7 @@
                 strcpy(scan_array[index].ap_EncryptionMode, "AES");
             }
         }
+        ret = fgets(line, sizeof(line), f);
     }
 
     if (!filter_BSS) {
@@ -3696,7 +3703,6 @@
         *output_array_size = index;
     }
     *neighbor_ap_array = scan_array;
-    free(line);
     pclose(f);
     WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
     return RETURN_OK;
@@ -4346,42 +4352,129 @@
 // outputs A-MSDU enable status, 0 == not enabled, 1 == enabled
 INT wifi_getRadioAMSDUEnable(INT radioIndex, BOOL *output_bool)
 {
-    return RETURN_ERR;
+    char AMSDU_file_path[64] = {0};
+
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+
+    if(output_bool == NULL)
+        return RETURN_ERR;
+
+    sprintf(AMSDU_file_path, "%s%d.txt", AMSDU_FILE, radioIndex);
+
+    if (access(AMSDU_file_path, F_OK) == 0)
+        *output_bool = TRUE;
+    else
+        *output_bool = FALSE;
+
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
+    return RETURN_OK;
 }
 
 // enables A-MSDU in the hardware, 0 == not enabled, 1 == enabled
 INT wifi_setRadioAMSDUEnable(INT radioIndex, BOOL amsduEnable)
 {
-    //Apply instantly
-    return RETURN_ERR;
+    char cmd[64]={0};
+    char buf[64]={0};
+    char AMSDU_file_path[64] = {0};
+
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+
+    sprintf(cmd, "mt76-vendor %s%d set ap_wireless amsdu=%d", AP_PREFIX, radioIndex, amsduEnable);
+    _syscmd(cmd, buf, sizeof(buf));
+
+    sprintf(AMSDU_file_path, "%s%d.txt", AMSDU_FILE, radioIndex);
+    memset(cmd, 0, sizeof(cmd));
+    if (amsduEnable == TRUE)
+        sprintf(cmd, "touch %s", AMSDU_file_path);
+    else
+        sprintf(cmd, "rm %s 2> /dev/null", AMSDU_file_path);
+    _syscmd(cmd, buf, sizeof(buf));
+
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
+    return RETURN_OK;
 }
 
 //P2  // outputs the number of Tx streams
 INT wifi_getRadioTxChainMask(INT radioIndex, INT *output_int)
 {
-    return RETURN_ERR;
+    char buf[8] = {0};
+    char cmd[128] = {0};
+
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+
+    sprintf(cmd, "cat %s%d.txt 2> /dev/null", CHAIN_MASK_FILE, radioIndex);
+    _syscmd(cmd, buf, sizeof(buf));
+
+    // if there is no record, output the max number of spatial streams
+    if (strlen(buf) == 0) {
+        sprintf(cmd, "iw phy%d info | grep 'TX MCS and NSS set' -A8 | head -n8 | grep 'streams: MCS' | wc -l", radioIndex);
+        _syscmd(cmd, buf, sizeof(buf));
+    }
+
+    *output_int = (INT)strtol(buf, NULL, 10);
+
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
+
+    return RETURN_OK;
 }
 
 //P2  // sets the number of Tx streams to an enviornment variable
 INT wifi_setRadioTxChainMask(INT radioIndex, INT numStreams)
 {
-    //save to wifi config, wait for wifi reset or wifi_pushTxChainMask to apply
-    return RETURN_ERR;
+    char cmd[128] = {0};
+    char buf[128] = {0};
+    char chain_mask_file[128] = {0};
+    FILE *f = NULL;
+
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+
+    if (numStreams == 0) {
+        fprintf(stderr, "The mask did not support 0 (auto).\n", numStreams);
+        return RETURN_ERR;
+    }
+    wifi_setRadioEnable(radioIndex, FALSE);
+    sprintf(cmd, "iw phy%d set antenna 0x%x 2>&1", radioIndex, numStreams);
+    _syscmd(cmd, buf, sizeof(buf));
+
+    if (strlen(buf) > 0) {
+        fprintf(stderr, "%s: cmd %s error, output: %s\n", __func__, cmd, buf);
+        return RETURN_ERR;
+    }
+    wifi_setRadioEnable(radioIndex, TRUE);
+
+    sprintf(chain_mask_file, "%s%d.txt", CHAIN_MASK_FILE, radioIndex);
+    f = fopen(chain_mask_file, "w");
+    if (f == NULL) {
+        fprintf(stderr, "%s: fopen failed.\n", __func__);
+        return RETURN_ERR;
+    }
+    fprintf(f, "%d", numStreams);
+    fclose(f);
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
+    return RETURN_OK;
 }
 
 //P2  // outputs the number of Rx streams
 INT wifi_getRadioRxChainMask(INT radioIndex, INT *output_int)
 {
-    if (NULL == output_int)
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+    if (wifi_getRadioTxChainMask(radioIndex, output_int) == RETURN_ERR) {
+        fprintf(stderr, "%s: wifi_getRadioTxChainMask return error.\n", __func__);
         return RETURN_ERR;
-    *output_int = 1;
+    }
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
     return RETURN_OK;
 }
 
 //P2  // sets the number of Rx streams to an enviornment variable
 INT wifi_setRadioRxChainMask(INT radioIndex, INT numStreams)
 {
-    //save to wifi config, wait for wifi reset or wifi_pushRxChainMask to apply
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+    if (wifi_setRadioTxChainMask(radioIndex, numStreams) == RETURN_ERR) {
+        fprintf(stderr, "%s: wifi_setRadioTxChainMask return error.\n", __func__);
+        return RETURN_ERR;
+    }
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
     return RETURN_ERR;
 }
 
@@ -5343,12 +5436,64 @@
 // reset the vlan configuration for this ap
 INT wifi_resetApVlanCfg(INT apIndex)
 {
-    //TODO: remove existing vlan for this ap
+    char original_config_file[64] = {0};
+    char current_config_file[64] = {0};
+    char buf[64] = {0};
+    char cmd[64] = {0};
+    char vlan_file[64] = {0};
+    char vlan_tagged_interface[16] = {0};
+    char vlan_bridge[16] = {0};
+    char vlan_naming[16] = {0};
+    struct params list[4] = {0};
+    wifi_band band;
+
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+
+    band = wifi_index_to_band(apIndex);
+    if (band == band_2_4)
+        sprintf(original_config_file, "/etc/hostapd-2G.conf");
+    else if (band = band_5)
+        sprintf(original_config_file, "/etc/hostapd-5G.conf");
+    else if (band = band_6)
+        sprintf(original_config_file, "/etc/hostapd-6G.conf");
+
+    wifi_hostapdRead(original_config_file, "vlan_file", vlan_file, sizeof(vlan_file));
+
+    if (strlen(vlan_file) == 0)
+        strcpy(vlan_file, VLAN_FILE);
 
+    // The file should exist or this vap would not work.
+    if (access(vlan_file, F_OK) != 0) {
+        sprintf(cmd, "touch %s", vlan_file);
+        _syscmd(cmd, buf, sizeof(buf));
+    }
+    list[0].name = "vlan_file";
+    list[0].value = vlan_file;
+
+    wifi_hostapdRead(original_config_file, "vlan_tagged_interface", vlan_tagged_interface, sizeof(vlan_tagged_interface));
+    list[1].name = "vlan_tagged_interface";
+    list[1].value = vlan_tagged_interface;
+
+    wifi_hostapdRead(original_config_file, "vlan_bridge", vlan_bridge, sizeof(vlan_bridge));
+    list[2].name = "vlan_bridge";
+    list[2].value = vlan_bridge;
+
+    wifi_hostapdRead(original_config_file, "vlan_naming", vlan_naming, sizeof(vlan_naming));
+    list[3].name = "vlan_naming";
+    list[3].value = vlan_naming;
+
+    sprintf(current_config_file, "%s%d.conf", CONFIG_PREFIX, apIndex);
+    wifi_hostapdWrite(current_config_file, list, 4);
     //Reapply vlan settings
-    wifi_pushBridgeInfo(apIndex);
+    // wifi_pushBridgeInfo(apIndex);
 
-    return RETURN_ERR;
+    // restart this ap
+    wifi_setApEnable(apIndex, FALSE);
+    wifi_setApEnable(apIndex, TRUE);
+
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
+
+    return RETURN_OK;
 }
 
 // creates configuration variables needed for WPA/WPS.  These variables are implementation dependent and in some implementations these variables are used by hostapd when it is started.  Specific variables that are needed are dependent on the hostapd implementation. These variables are set by WPA/WPS security functions in this wifi HAL.  If not needed for a particular implementation this function may simply return no error.
@@ -5999,8 +6144,71 @@
 //When set to true, this AccessPoint instance's WiFi security settings are reset to their factory default values. The affected settings include ModeEnabled, WEPKey, PreSharedKey and KeyPassphrase.
 INT wifi_setApSecurityReset(INT apIndex)
 {
-    //apply instantly
-    return RETURN_ERR;
+    char original_config_file[64] = {0};
+    char current_config_file[64] = {0};
+    char buf[64] = {0};
+    char cmd[64] = {0};
+    char wpa[4] = {0};
+    char wpa_psk[64] = {0};
+    char wpa_passphrase[64] = {0};
+    char wpa_psk_file[128] = {0};
+    char wpa_key_mgmt[64] = {0};
+    char wpa_pairwise[32] = {0};
+    wifi_band band;
+    struct params list[6];
+
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+
+    band = wifi_index_to_band(apIndex);
+    if (band == band_2_4)
+        sprintf(original_config_file, "/etc/hostapd-2G.conf");
+    else if (band = band_5)
+        sprintf(original_config_file, "/etc/hostapd-5G.conf");
+    else if (band = band_6)
+        sprintf(original_config_file, "/etc/hostapd-6G.conf");
+    else
+        return RETURN_ERR;
+
+    wifi_hostapdRead(original_config_file, "wpa", wpa, sizeof(wpa));
+    list[0].name = "wpa";
+    list[0].value = wpa;
+    
+    wifi_hostapdRead(original_config_file, "wpa_psk", wpa_psk, sizeof(wpa_psk));
+    list[1].name = "wpa_psk";
+    list[1].value = wpa_psk;
+
+    wifi_hostapdRead(original_config_file, "wpa_passphrase", wpa_passphrase, sizeof(wpa_passphrase));
+    list[2].name = "wpa_passphrase";
+    list[2].value = wpa_passphrase;
+
+    wifi_hostapdRead(original_config_file, "wpa_psk_file", wpa_psk_file, sizeof(wpa_psk_file));
+
+    if (strlen(wpa_psk_file) == 0)
+        strcpy(wpa_psk_file, PSK_FILE);
+
+    if (access(wpa_psk_file, F_OK) != 0) {
+        sprintf(cmd, "touch %s", wpa_psk_file);
+        _syscmd(cmd, buf, sizeof(buf));
+    }
+    list[3].name = "wpa_psk_file";
+    list[3].value = wpa_psk_file;
+
+    wifi_hostapdRead(original_config_file, "wpa_key_mgmt", wpa_key_mgmt, sizeof(wpa_key_mgmt));
+    list[4].name = "wpa_key_mgmt";
+    list[4].value = wpa_key_mgmt;
+
+    wifi_hostapdRead(original_config_file, "wpa_pairwise", wpa_pairwise, sizeof(wpa_pairwise));
+    list[5].name = "wpa_pairwise";
+    list[5].value = wpa_pairwise;
+
+    sprintf(current_config_file, "%s%d.conf", CONFIG_PREFIX, apIndex);
+    wifi_hostapdWrite(current_config_file, list, 6);
+
+    wifi_setApEnable(apIndex, FALSE);
+    wifi_setApEnable(apIndex, TRUE);
+
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
+    return RETURN_OK;
 }
 
 //The IP Address and port number of the RADIUS server used for WLAN security. RadiusServerIPAddr is only applicable when ModeEnabled is an Enterprise type (i.e. WPA-Enterprise, WPA2-Enterprise or WPA-WPA2-Enterprise).
@@ -7939,112 +8147,205 @@
 
 INT wifi_getNeighboringWiFiStatus(INT radio_index, wifi_neighbor_ap2_t **neighbor_ap_array, UINT *output_array_size)
 {
-    char cmd[1024] =  {0};
-    char buf[1024] = {0};
-    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+    int index = -1;
     wifi_neighbor_ap2_t *scan_array = NULL;
-    int scan_count=0;
-    int i =0;
+    char cmd[256]={0};
+    char buf[128]={0};
+    char file_name[32] = {0};
+    char filter_SSID[32] = {0};
+    char line[256] = {0};
+    char *ret = NULL;
     int freq=0;
-    size_t len=0;
     FILE *f = NULL;
-    ssize_t read = 0;
-    char *line =NULL;
-    char radio_ifname[64];
-    char secondary_chan[64];
+    size_t len=0;
+    int channels_num = 0;
     int vht_channel_width = 0;
+    bool get_nosie_ret = false;
+    bool filter_enable = false;
+    bool filter_BSS = false;     // The flag determine whether the BSS information need to be filterd.
 
-    if(wifi_getRadioIfName(radio_index,radio_ifname)!=RETURN_OK)
-        return RETURN_ERR;
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s: %d\n", __func__, __LINE__);
 
-    /* sched_start is not supported on open source ath9k ath10k firmware
-     * Using active scan as a workaround */
-    sprintf(cmd,"iw dev %s scan |grep '^BSS\\|SSID:\\|freq:\\|signal:\\|HT operation:\\|secondary channel offset:\\|* channel width:'", radio_ifname);
-    if((f = popen(cmd, "r")) == NULL) {
+    snprintf(file_name, sizeof(file_name), "%s%d.txt", ESSID_FILE, radio_index);
+    f = fopen(file_name, "r");
+    if (f != NULL) {
+        fgets(filter_SSID, sizeof(file_name), f);
+        if (strlen(filter_SSID) != 0)
+            filter_enable = true;
+        fclose(f);
+    }
+
+    snprintf(cmd, sizeof(cmd), "iw phy phy%d channels | grep * | grep -v disable | wc -l", radio_index);
+    _syscmd(cmd, buf, sizeof(buf));
+    channels_num = strtol(buf, NULL, 10);
+
+    struct channels_noise *channels_noise_arr = calloc(channels_num, sizeof(struct channels_noise));
+    get_nosie_ret = get_noise(radio_index, channels_noise_arr, channels_num);
+
+    sprintf(cmd, "iw dev %s%d scan dump | grep '%s%d\\|SSID\\|freq\\|beacon interval\\|capabilities\\|signal\\|Supported rates\\|DTIM\\| \
+    // WPA\\|RSN\\|Group cipher\\|HT operation\\|secondary channel offset\\|channel width\\|HE.*GHz' | grep -v -e '*.*BSS'", AP_PREFIX, radio_index, AP_PREFIX, radio_index);
+    fprintf(stderr, "cmd: %s\n", cmd);
+    if ((f = popen(cmd, "r")) == NULL) {
         wifi_dbg_printf("%s: popen %s error\n", __func__, cmd);
         return RETURN_ERR;
     }
-    read = getline(&line, &len, f);
-    while (read  != -1) {
-        if(strncmp(line,"BSS",3) == 0) {
-            i = scan_count;
-            scan_count++;
-            scan_array = realloc(scan_array,sizeof(wifi_neighbor_ap2_t)*scan_count);
-            memset(&(scan_array[i]),0, sizeof(wifi_neighbor_ap2_t));
-            sscanf(line,"BSS %17s", scan_array[i].ap_BSSID);
+    ret = fgets(line, sizeof(line), f);
+    while (ret != NULL) {
+        if(strstr(line, "BSS") != NULL) {    // new neighbor info
+            // The SSID field is not in the first field. So, we should store whole BSS informations and the filter flag. 
+            // And we will determine whether we need the previous BSS infomation when parsing the next BSS field or end of while loop.
+            // If we don't want the BSS info, we don't realloc more space, and just clean the previous BSS.
 
-            read = getline(&line, &len, f);
+            if (!filter_BSS) {
+                index++;
+                wifi_neighbor_ap2_t *tmp;
+                tmp = realloc(scan_array, sizeof(wifi_neighbor_ap2_t)*(index+1));
+                if (tmp == NULL) {              // no more memory to use
+                    index--;
+                    wifi_dbg_printf("%s: realloc failed\n", __func__);
+                    break;
+                }
+                scan_array = tmp;
+            }
+            memset(&(scan_array[index]), 0, sizeof(wifi_neighbor_ap2_t));
+
+            filter_BSS = false;
+            sscanf(line, "BSS %17s", scan_array[index].ap_BSSID);
+            strncpy(scan_array[index].ap_Mode, "Infrastructure", strlen("Infrastructure"));
+            strncpy(scan_array[index].ap_SecurityModeEnabled, "None", strlen("None"));
+            strncpy(scan_array[index].ap_EncryptionMode, "None", strlen("None"));
+        } else if (strstr(line, "freq") != NULL) {
             sscanf(line,"	freq: %d", &freq);
-            scan_array[i].ap_Channel = ieee80211_frequency_to_channel(freq);
+            scan_array[index].ap_Channel = ieee80211_frequency_to_channel(freq);
 
-            read = getline(&line, &len, f);
-            sscanf(line,"	signal: %d", &(scan_array[i].ap_SignalStrength));
+            if (freq >= 2412 && freq <= 2484) {
+                strncpy(scan_array[index].ap_OperatingFrequencyBand, "2.4GHz", strlen("2.4GHz"));
+                strncpy(scan_array[index].ap_SupportedStandards, "b,g", strlen("b,g"));
+                strncpy(scan_array[index].ap_OperatingStandards, "g", strlen("g"));
+            }
+            else if (freq >= 5160 && freq <= 5805) {
+                strncpy(scan_array[index].ap_OperatingFrequencyBand, "5GHz", strlen("5GHz"));
+                strncpy(scan_array[index].ap_SupportedStandards, "a", strlen("a"));
+                strncpy(scan_array[index].ap_OperatingStandards, "a", strlen("a"));
+            }
 
-            read = getline(&line, &len, f);
-            sscanf(line,"	SSID: %s", scan_array[i].ap_SSID);
-            wifi_dbg_printf("%s:Discovered BSS %s, %d, %d , %s\n", __func__, scan_array[i].ap_BSSID, scan_array[i].ap_Channel,scan_array[i].ap_SignalStrength, scan_array[i].ap_SSID);
-            read = getline(&line, &len, f);
-            if(strncmp(line,"BSS",3)==0) {
-                // No HT and no VHT => 20Mhz
-                snprintf(scan_array[i].ap_OperatingChannelBandwidth, sizeof(scan_array[i].ap_OperatingChannelBandwidth), "11%s", radio_index%1 ? "A": "G");
-                wifi_dbg_printf("%s: ap_OperatingChannelBandwidth = '%s'\n", __func__, scan_array[i].ap_OperatingChannelBandwidth);
-                continue;
+            scan_array[index].ap_Noise = 0;
+            if (get_nosie_ret) {
+                for (int i = 0; i < channels_num; i++) {
+                    if (scan_array[index].ap_Channel == channels_noise_arr[i].channel) {
+                        scan_array[index].ap_Noise = channels_noise_arr[i].noise;
+                        break;
+                    }
+                }
             }
-            if(strncmp(line,"	HT operation:",14)!= 0) {
-                    wifi_dbg_printf("HT output parsing error (%s)\n", line);
-                    goto output_error;
+        } else if (strstr(line, "beacon interval") != NULL) {
+            sscanf(line,"	beacon interval: %d TUs", &(scan_array[index].ap_BeaconPeriod));
+        } else if (strstr(line, "signal") != NULL) {
+            sscanf(line,"	signal: %d", &(scan_array[index].ap_SignalStrength));
+        } else if (strstr(line,"SSID") != NULL) {
+            sscanf(line,"	SSID: %s", scan_array[index].ap_SSID);
+            if (filter_enable && strcmp(scan_array[index].ap_SSID, filter_SSID) != 0) {
+                filter_BSS = true;
             }
+        } else if (strstr(line, "Supported rates") != NULL) {
+            char SRate[80] = {0}, *tmp = NULL;
+            memset(buf, 0, sizeof(buf));
+            strcpy(SRate, line);
+            tmp = strtok(SRate, ":");
+            tmp = strtok(NULL, ":");
+            strcpy(buf, tmp);
+            memset(SRate, 0, sizeof(SRate));
 
-            read = getline(&line, &len, f);
-            sscanf(line,"		 * secondary channel offset: %s", &secondary_chan);
+            tmp = strtok(buf, " \n");
+            while (tmp != NULL) {
+                strcat(SRate, tmp);
+                if (SRate[strlen(SRate) - 1] == '*') {
+                    SRate[strlen(SRate) - 1] = '\0';
+                }
+                strcat(SRate, ",");
 
-            if(!strcmp(secondary_chan, "no")) {
-                //20Mhz
-                snprintf(scan_array[i].ap_OperatingChannelBandwidth, sizeof(scan_array[i].ap_OperatingChannelBandwidth), "11N%s_HT20", radio_index%1 ? "A": "G");
+                tmp = strtok(NULL, " \n");
             }
-
-            if(!strcmp(secondary_chan, "above")) {
+            SRate[strlen(SRate) - 1] = '\0';
+            strcpy(scan_array[index].ap_SupportedDataTransferRates, SRate);
+        } else if (strstr(line, "DTIM") != NULL) {
+            sscanf(line,"DTIM Period %d", scan_array[index].ap_DTIMPeriod, buf);
+        } else if (strstr(line, "VHT capabilities") != NULL) {
+            strcat(scan_array[index].ap_SupportedStandards, ",ac");
+            strcpy(scan_array[index].ap_OperatingStandards, "ac");
+        } else if (strstr(line, "HT capabilities") != NULL) {
+            strcat(scan_array[index].ap_SupportedStandards, ",n");
+            strcpy(scan_array[index].ap_OperatingStandards, "n");
+        } else if (strstr(line, "VHT operation") != NULL) {
+            ret = fgets(line, sizeof(line), f);
+            sscanf(line,"		 * channel width: %d", &vht_channel_width);
+            if(vht_channel_width == 1) {
+                snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11AC_VHT80");
+            } else {
+                snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11AC_VHT40");
+            }
+            if (strstr(line, "BSS") != NULL)   // prevent to get the next neighbor information
+                continue;
+        } else if (strstr(line, "HT operation") != NULL) {
+            ret = fgets(line, sizeof(line), f);
+            sscanf(line,"		 * secondary channel offset: %s", &buf);
+            if (!strcmp(buf, "above")) {
                 //40Mhz +
-                snprintf(scan_array[i].ap_OperatingChannelBandwidth, sizeof(scan_array[i].ap_OperatingChannelBandwidth), "11N%s_HT40PLUS", radio_index%1 ? "A": "G");
+                snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11N%s_HT40PLUS", radio_index%1 ? "A": "G");
             }
-
-            if(!strcmp(secondary_chan, "below")) {
+            else if (!strcmp(buf, "below")) {
                 //40Mhz -
-                snprintf(scan_array[i].ap_OperatingChannelBandwidth, sizeof(scan_array[i].ap_OperatingChannelBandwidth), "11N%s_HT40MINUS", radio_index%1 ? "A": "G");
+                snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11N%s_HT40MINUS", radio_index%1 ? "A": "G");
+            } else {
+                //20Mhz
+                snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11N%s_HT20", radio_index%1 ? "A": "G");
             }
-
-
-            read = getline(&line, &len, f);
-            if(strncmp(line,"	VHT operation:",15) !=0) {
-                wifi_dbg_printf("%s: ap_OperatingChannelBandwidth = '%s'\n", __func__, scan_array[i].ap_OperatingChannelBandwidth);
-                // No VHT
+            if (strstr(line, "BSS") != NULL)   // prevent to get the next neighbor information
                 continue;
+        } else if (strstr(line, "HE capabilities") != NULL) {
+            strcat(scan_array[index].ap_SupportedStandards, ",ax");
+            strcpy(scan_array[index].ap_OperatingStandards, "ax");
+            ret = fgets(line, sizeof(line), f);
+            if (strncmp(scan_array[index].ap_OperatingFrequencyBand, "2.4GHz", strlen("2.4GHz")) == 0) {
+                if (strstr(line, "HE40/2.4GHz") != NULL)
+                    strcpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE40PLUS");
+                else
+                    strcpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE20");
+            } else if (strncmp(scan_array[index].ap_OperatingFrequencyBand, "5GHz", strlen("5GHz")) == 0) {
+                if (strstr(line, "HE80/5GHz") != NULL) {
+                    strcpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE80");
+                    ret = fgets(line, sizeof(line), f);
+                } else
+                    continue;
+                if (strstr(line, "HE160/5GHz") != NULL)
+                    strcpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE160");
             }
-            read = getline(&line, &len, f);
-            sscanf(line,"		 * channel width: %d", &vht_channel_width);
-            if(vht_channel_width == 1) {
-                snprintf(scan_array[i].ap_OperatingChannelBandwidth, sizeof(scan_array[i].ap_OperatingChannelBandwidth), "11AC_VHT80");
-            } else {
-                snprintf(scan_array[i].ap_OperatingChannelBandwidth, sizeof(scan_array[i].ap_OperatingChannelBandwidth), "11AC_VHT40");
+            continue;
+        } else if (strstr(line, "WPA") != NULL) {
+            strcpy(scan_array[index].ap_SecurityModeEnabled, "WPA");
+        } else if (strstr(line, "RSN") != NULL) {
+            strcpy(scan_array[index].ap_SecurityModeEnabled, "RSN");
+        } else if (strstr(line, "Group cipher") != NULL) {
+            sscanf(line, "		 * Group cipher: %s", scan_array[index].ap_EncryptionMode);
+            if (strncmp(scan_array[index].ap_EncryptionMode, "CCMP", strlen("CCMP")) == 0) {
+                strcpy(scan_array[index].ap_EncryptionMode, "AES");
             }
-
         }
-        wifi_dbg_printf("%s: ap_OperatingChannelBandwidth = '%s'\n", __func__, scan_array[i].ap_OperatingChannelBandwidth);
-        read = getline(&line, &len, f);
+        ret = fgets(line, sizeof(line), f);
     }
-    wifi_dbg_printf("%s:Counted BSS: %d\n",__func__, scan_count);
-    *output_array_size = scan_count;
+
+    if (!filter_BSS) {
+        *output_array_size = index + 1;
+    } else {
+        memset(&(scan_array[index]), 0, sizeof(wifi_neighbor_ap2_t));
+        *output_array_size = index;
+    }
     *neighbor_ap_array = scan_array;
-    free(line);
     pclose(f);
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
     return RETURN_OK;
-
-output_error:
-    pclose(f);
-    free(line);
-    free(scan_array);
-    return RETURN_ERR;
 }
+
 INT wifi_getApAssociatedDeviceStats(
         INT apIndex,
         mac_address_t *clientMacAddress,
@@ -8722,7 +9023,25 @@
 
 INT wifi_startNeighborScan(INT apIndex, wifi_neighborScanMode_t scan_mode, INT dwell_time, UINT chan_num, UINT *chan_list)
 {
-    // TODO Implement me!
+    char cmd[128]={0};
+    char buf[128]={0};
+    int freq = 0;
+
+    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
+
+    // full mode is used to scan all channels.
+    // multiple channels is ambiguous, iw can not set multiple frequencies in one time.
+    if (scan_mode != WIFI_RADIO_SCAN_MODE_FULL)
+        ieee80211_channel_to_frequency(chan_list[0], &freq);
+
+    if (freq)
+        snprintf(cmd, sizeof(cmd), "iw dev %s%d scan trigger duration %d freq %d", AP_PREFIX, apIndex, dwell_time, freq);
+    else
+        snprintf(cmd, sizeof(cmd), "iw dev %s%d scan trigger duration %d", AP_PREFIX, apIndex, dwell_time);
+
+    _syscmd(cmd, buf, sizeof(buf));
+    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
+
     return RETURN_OK;
 }