[rdk-b][mt7986][wifi-hal][Refactor Neighbor scan function]

[Description]
1. Refactor NeighboringWiFiDiagnosticResult2 function scan part by parsing iw scan output.
2. Add scan filter function and refactor Neighbor scan function. We will only output the BSS info according to the SSID store in ESSID_FILE. The SSID is setted by setApScanFilter function.

[Release-log]
N/A

Change-Id: I734f7753443753f56190e66dc924bf479773a086
diff --git a/recipes-ccsp/hal/hal-wifi-patches/0034-HAL-refactor-NeighboringWiFiDiagnosticResult2-scan-p.patch b/recipes-ccsp/hal/hal-wifi-patches/0034-HAL-refactor-NeighboringWiFiDiagnosticResult2-scan-p.patch
new file mode 100644
index 0000000..4f862e8
--- /dev/null
+++ b/recipes-ccsp/hal/hal-wifi-patches/0034-HAL-refactor-NeighboringWiFiDiagnosticResult2-scan-p.patch
@@ -0,0 +1,339 @@
+From 4592e371528abdf4804c116760059b0a0fb4dbc6 Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Tue, 2 Aug 2022 17:23:06 +0800
+Subject: [PATCH] HAL: refactor NeighboringWiFiDiagnosticResult2 scan part and
+ add scan filter function
+
+---
+ source/wifi/wifi_hal.c | 289 ++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 259 insertions(+), 30 deletions(-)
+
+diff --git a/source/wifi/wifi_hal.c b/source/wifi/wifi_hal.c
+index e49f22f..44f167b 100644
+--- a/source/wifi/wifi_hal.c
++++ b/source/wifi/wifi_hal.c
+@@ -73,6 +73,8 @@ Licensed under the ISC license
+ //#define ACL_PREFIX "/tmp/wifi_acl_list" //RDKB convention
+ #define SOCK_PREFIX "/var/run/hostapd/wifi"
+ #define VAP_STATUS_FILE "/tmp/vap-status"
++#define ESSID_FILE "/tmp/essid"
++
+ #ifdef MTK_IMPL
+ #define DRIVER_2GHZ "mt7915e"
+ #define DRIVER_5GHZ "mt7915e"
+@@ -3037,47 +3039,243 @@ INT wifi_applySSIDSettings(INT ssidIndex)
+     return ret;
+ }
+ 
++struct channels_noise {
++    int channel;
++    int noise;
++};
++
++// Return noise array for each channel
++int get_noise(int radioIndex, struct channels_noise *channels_noise_arr, int channels_num)
++{
++    FILE *f = NULL;
++    char cmd[128] = {0};
++    char *line = NULL;
++    size_t len = 0;
++    ssize_t read = 0;
++    int tmp = 0, arr_index = -1;
++
++    sprintf(cmd, "iw dev %s%d survey dump | grep 'frequency\\|noise' | awk '{print $2}'", AP_PREFIX, radioIndex);
++
++    if ((f = popen(cmd, "r")) == NULL) {
++        wifi_dbg_printf("%s: popen %s error\n", __func__, cmd);
++        return RETURN_ERR;
++    }
++    
++    while((read = getline(&line, &len, f)) != -1) {
++        sscanf(line, "%d", &tmp);
++        if (tmp > 0) {      // channel frequency, the first line must be frequency
++            arr_index++;
++            channels_noise_arr[arr_index].channel = ieee80211_frequency_to_channel(tmp);
++        } else {            // noise
++            channels_noise_arr[arr_index].noise = tmp;
++        }
++    }
++    free(line);
++    pclose(f);
++    return RETURN_OK;
++}
++
+ //Start the wifi scan and get the result into output buffer for RDKB to parser. The result will be used to manage endpoint list
+ //HAL funciton should allocate an data structure array, and return to caller with "neighbor_ap_array"
+ INT wifi_getNeighboringWiFiDiagnosticResult2(INT radioIndex, wifi_neighbor_ap2_t **neighbor_ap_array, UINT *output_array_size) //Tr181	
+ {
+-    INT status = RETURN_ERR;
+-    UINT index;
+-    wifi_neighbor_ap2_t *pt=NULL;
+-    char cmd[128]={0};
+-    char buf[8192]={0};
++    int index = -1;
++    wifi_neighbor_ap2_t *scan_array = NULL;
++    char cmd[256]={0};
++    char buf[128]={0};
++    char file_name[32] = {0};
++    char filter_SSID[32] = {0};
++    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__);
+-    sprintf(cmd, "iwlist %s%d scan",AP_PREFIX,(radioIndex==0)?0:1);	//suppose ap0 mapping to radio0
++
++    snprintf(file_name, sizeof(file_name), "%s%d.txt", ESSID_FILE, radioIndex);
++    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", radioIndex);
+     _syscmd(cmd, buf, sizeof(buf));
++    channels_num = atoi(buf);
+ 
++    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);
++    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;
++    }
+ 
+-    *output_array_size=2;
+-    //zqiu: HAL alloc the array and return to caller. Caller response to free it.
+-    *neighbor_ap_array=(wifi_neighbor_ap2_t *)calloc(sizeof(wifi_neighbor_ap2_t), *output_array_size);
+-    for (index = 0, pt=*neighbor_ap_array; index < *output_array_size; index++, pt++) {
+-        strcpy(pt->ap_SSID,"");
+-        strcpy(pt->ap_BSSID,"");
+-        strcpy(pt->ap_Mode,"");
+-        pt->ap_Channel=1;
+-        pt->ap_SignalStrength=0;
+-        strcpy(pt->ap_SecurityModeEnabled,"");
+-        strcpy(pt->ap_EncryptionMode,"");
+-        strcpy(pt->ap_OperatingFrequencyBand,"");
+-        strcpy(pt->ap_SupportedStandards,"");
+-        strcpy(pt->ap_OperatingStandards,"");
+-        strcpy(pt->ap_OperatingChannelBandwidth,"");
+-        pt->ap_BeaconPeriod=1;
+-        pt->ap_Noise=0;
+-        strcpy(pt->ap_BasicDataTransferRates,"");
+-        strcpy(pt->ap_SupportedDataTransferRates,"");
+-        pt->ap_DTIMPeriod=1;
+-        pt->ap_ChannelUtilization=0;
++    while ((read = getline(&line, &len, f)) != -1) {
++        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.
++
++            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[index].ap_Channel = ieee80211_frequency_to_channel(freq);
++
++            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"));
++            }
++
++            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;
++                    }
++                }
++            }
++        } 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[64] = {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));
++
++            tmp = strtok(buf, " \n");
++            while (tmp != NULL) {
++                strcat(SRate, tmp);
++                if (SRate[strlen(SRate) - 1] == '*') {
++                    SRate[strlen(SRate) - 1] = '\0';
++                }
++                strcat(SRate, ",");
++
++                tmp = strtok(NULL, " \n");
++            }
++            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) {
++            read = getline(&line, &len, 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) {
++            read = getline(&line, &len, f);
++            sscanf(line,"		 * secondary channel offset: %s", &buf);
++            if (!strcmp(buf, "above")) {
++                //40Mhz +
++                snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11N%s_HT40PLUS", radioIndex%1 ? "A": "G");
++            }
++            else if (!strcmp(buf, "below")) {
++                //40Mhz -
++                snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11N%s_HT40MINUS", radioIndex%1 ? "A": "G");
++            } else {
++                //20Mhz
++                snprintf(scan_array[index].ap_OperatingChannelBandwidth, sizeof(scan_array[index].ap_OperatingChannelBandwidth), "11N%s_HT20", radioIndex%1 ? "A": "G");
++            }
++            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) {
++            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"));
++                else
++                    strncpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE20", strlen("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, "HE160/5GHz") != NULL)
++                    strncpy(scan_array[index].ap_OperatingChannelBandwidth, "11AXHE160", strlen("11AXHE160"));
++            }
++            if (strstr(line, "BSS") != NULL)   // prevent to get the next neighbor information
++                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");
++            }
++        }
+     }
+ 
+-    status = RETURN_OK;
++    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 status;
++    return RETURN_OK;
+ }
+ 
+ //>> Deprecated: used for old RDKB code.
+@@ -7635,7 +7833,38 @@ INT wifi_setApCsaDeauth(INT apIndex, INT mode)
+ 
+ INT wifi_setApScanFilter(INT apIndex, INT mode, CHAR *essid)
+ {
+-    // TODO Implement me!
++    char file_name[128] = {0};
++    char buf[128] = {0};
++    FILE *f = NULL;
++
++    WIFI_ENTRY_EXIT_DEBUG("Inside %s:%d\n",__func__, __LINE__);
++
++    if (essid == NULL || strlen(essid) == 0 || apIndex == -1) {
++        for (int index = 0; index < NUMBER_OF_RADIOS; index++) {
++            snprintf(file_name, sizeof(file_name), "%s%d.txt", ESSID_FILE, index);
++            f = fopen(file_name, "w");
++            if (f == NULL) 
++                return RETURN_ERR;
++            // For mode == 0 is to disable filter, just don't write to the file.
++            if (mode)
++                fprintf(f, "%s", essid);
++
++            fclose(f);
++        }
++    } else {        // special case, need to set AP's SSID as filter for each radio.
++        snprintf(file_name, sizeof(file_name), "%s%d.txt", ESSID_FILE, apIndex);
++        f = fopen(file_name, "w");
++        if (f == NULL) 
++            return RETURN_ERR;
++
++        // For mode == 0 is to disable filter, just don't write to the file.
++        if (mode)
++            fprintf(f, "%s", essid);
++
++        fclose(f);
++    }
++    
++    WIFI_ENTRY_EXIT_DEBUG("Exiting %s:%d\n",__func__, __LINE__);
+     return RETURN_OK;
+ }
+ 
+-- 
+2.18.0
+