diff options
author | lesl <lesl@google.com> | 2019-10-30 15:16:12 +0800 |
---|---|---|
committer | lesl <lesl@google.com> | 2019-12-13 14:27:48 +0800 |
commit | 311b8a6a3d8ee1ddd1afe28e8ccd07c1a6b55775 (patch) | |
tree | 5a85504f6180a2e2cb6763ea7b425643039778dc | |
parent | 675835ee5c8386e8942750829bca3dc4dd438788 (diff) | |
download | cuttlefish-modules-311b8a6a3d8ee1ddd1afe28e8ccd07c1a6b55775.tar.gz |
Cuttlefish Wifi: Add wifi simulation driverdeprecated/android-4.19-randroid-4.19-r
Support scan data simulation.
Bug: 139421123
Change-Id: I2e8b1382d00e8cdcc994ab20015df15e8c2fc5b6
Signed-off-by: lesl <lesl@google.com>
-rw-r--r-- | wlan_simulation/Kbuild | 2 | ||||
-rw-r--r-- | wlan_simulation/Makefile | 6 | ||||
-rw-r--r-- | wlan_simulation/virt_wifi_data.c | 295 | ||||
-rw-r--r-- | wlan_simulation/virt_wifi_data.h | 30 | ||||
-rw-r--r-- | wlan_simulation/virt_wifi_simulation.c | 282 | ||||
-rw-r--r-- | wlan_simulation/virt_wifi_simulation.h | 47 |
6 files changed, 662 insertions, 0 deletions
diff --git a/wlan_simulation/Kbuild b/wlan_simulation/Kbuild new file mode 100644 index 0000000..fdad86c --- /dev/null +++ b/wlan_simulation/Kbuild @@ -0,0 +1,2 @@ +obj-m += virt_wifi_sim.o +virt_wifi_sim-objs = virt_wifi_simulation.o virt_wifi_data.o diff --git a/wlan_simulation/Makefile b/wlan_simulation/Makefile new file mode 100644 index 0000000..2724d5e --- /dev/null +++ b/wlan_simulation/Makefile @@ -0,0 +1,6 @@ +all: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/wlan_simulation/virt_wifi_data.c b/wlan_simulation/virt_wifi_data.c new file mode 100644 index 0000000..b337ec0 --- /dev/null +++ b/wlan_simulation/virt_wifi_data.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/* virt_wifi_data.c + * + * Load simulation data from the file. + * + * Copyright (C) 2019 Google LLC + * + * Author: lesl@google.com + */ +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/uaccess.h> +#include <linux/slab.h> +#include "virt_wifi_simulation.h" +#include "virt_wifi_data.h" +#include <linux/device.h> +#include <linux/firmware.h> + +mm_segment_t oldfs; + +static int total_configured_ap_num; +static int total_configured_scan_result; +static struct access_point *ap_list[MAX_AP_NUM]; +static struct scan_config *scan_list[MAX_SCAN_CONFIG]; +static char scan_result_switch_factor; + +void free_scan_ap_info_list(struct list_head *apInfoList) +{ + struct scan_ap_info *pos, *next; + + list_for_each_entry_safe(pos, next, apInfoList, list) { + list_del(&pos->list); + kfree(pos); + } +} + +/* config_data format: + * 10;0,-55;1,-55; // Control Setting;AP_index,Ap_Rssi;AP2_index,AP2_Rssi; ... + */ +static struct scan_config *extract_scan_list_from_file(char *config_data) +{ + unsigned long val; + int parser_index = 0; + struct scan_ap_info *ap_info; + char *token_scan_list, *token_ap; + struct scan_config *config; + struct list_head *scan_list; + + config = kzalloc(sizeof(struct scan_config), GFP_KERNEL); + if (!config) + goto error; + scan_list = kzalloc(sizeof(struct list_head), GFP_KERNEL); + if (!scan_list) + goto error; + INIT_LIST_HEAD(scan_list); + + do { + token_scan_list = strsep(&config_data, ";"); + if (token_scan_list == NULL) + break; + if (parser_index == 0) { + kstrtoul(token_scan_list, 10, &val); + config->control_setting = val; + parser_index++; + continue; + } else if (strlen(token_scan_list) <= 1) { // ignore "\n" + continue; + } + parser_index = 0; + ap_info = kzalloc(sizeof(struct scan_ap_info), GFP_KERNEL); + if (!ap_info) + goto error; + do { + token_ap = strsep(&token_scan_list, ","); + if (token_ap != NULL) { + if (parser_index == 0) { + kstrtoul(token_ap, 10, &val); + ap_info->ap_index = val; + } else { + kstrtoul(token_ap + 1, 10, &val); + ap_info->signal = val * (-1); + } + parser_index++; + } + } while (token_ap != NULL); + list_add(&ap_info->list, scan_list); + } while (1); + config->scanList = scan_list; + return config; +error: + if (config) { + if (scan_list) { + free_scan_ap_info_list(scan_list); + kfree(scan_list); + } + kfree(config); + } + return NULL; +} + +static bool read_scan_config(struct device *dev) +{ + bool ret = false; + const struct firmware *fw_scan_config_entry; + int max_config_len; + struct scan_config *sc = NULL; + char *token, *buf = NULL, *tmp = NULL; + + if (request_firmware(&fw_scan_config_entry, + SCAN_CONTROL_CONFIG_FILE, dev)) { + pr_err("request_firmware: %s Firmware not available", + SCAN_CONTROL_CONFIG_FILE); + goto error; + } + buf = kzalloc(fw_scan_config_entry->size + 1, GFP_KERNEL); + if (!buf) + goto error; + memcpy(buf, fw_scan_config_entry->data, fw_scan_config_entry->size); + max_config_len = MAX_AP_NUM * MAX_AP_SCAN_CONFIG_LEN; + tmp = kzalloc(max_config_len + 1, GFP_KERNEL); + if (!tmp) + goto error; + do { + token = strsep(&buf, "\n"); + if (token == NULL || strlen(token) == 0) + break; + memset(tmp, 0, max_config_len + 1); + if (strlen(token) > max_config_len) + goto error; + strncpy(tmp, token, strlen(token)); + if (strlen(tmp) == 1) { + scan_result_switch_factor = tmp[0]; + } else { + sc = extract_scan_list_from_file(tmp); + if (!sc) + goto error; + scan_list[total_configured_scan_result] = sc; + total_configured_scan_result++; + if (total_configured_scan_result >= MAX_SCAN_CONFIG) + break; + } + } while (1); + ret = true; +error: + kfree(buf); + kfree(tmp); + if (fw_scan_config_entry) + release_firmware(fw_scan_config_entry); + return ret; +} + +/* ap_info format: + * index,bssid,security_type,channel,ssid + * example: + * 0,aa:bb:cc:dd:ee:ff,OPEN,5240,Test_SSID_1 + */ +static struct access_point *extract_ap_from_file(char *ap_info) +{ + unsigned long val; + int parser_index = 0; + char *token; + struct access_point *ap = kzalloc(sizeof(struct access_point), + GFP_KERNEL); + + if (!ap) + goto error; + do { + token = strsep(&ap_info, ","); + if (token == NULL) + break; + switch (parser_index) { + case 0: + kstrtoul(token, 10, &val); + ap->index = val; + break; + case 1: + if (strlen(token) <= sizeof(ap->bssid)) { + strncpy(ap->bssid, token, strlen(token)); + break; + } + case 2: + if (strlen(token) <= sizeof(ap->security_type)) { + strncpy(ap->security_type, token, + strlen(token)); + break; + } + case 3: + kstrtoul(token, 10, &val); + ap->channel = val; + break; + case 4: + if (strlen(token) < sizeof(ap->ssid)) { + strncpy(ap->ssid, token, strlen(token)); + break; + } + default: + pr_err("%s - parser error ", __func__); + kfree(ap); + ap = NULL; + break; + } + parser_index++; + } while (ap); +error: + return ap; +} + +static bool read_ap_config(struct device *dev) +{ + bool ret = false; + /** + * ap_config format is + * "index, bssid, security_type, channel, ssid" + * The buf len should be +2 for index and channel + * which type is not string. + */ + int buf_len = sizeof(struct access_point) + 2; + struct access_point *ap; + const struct firmware *fw_ap_config_entry; + char *token, *buf = NULL, *tmp = NULL; + + if (request_firmware(&fw_ap_config_entry, AP_LIST_CONFIG_FILE, dev)) { + pr_err("request_firmware: %s Firmware not available", + AP_LIST_CONFIG_FILE); + goto error; + } + buf = kzalloc(fw_ap_config_entry->size + 1, GFP_KERNEL); + if (!buf) + goto error; + memcpy(buf, fw_ap_config_entry->data, fw_ap_config_entry->size); + tmp = kzalloc(buf_len, GFP_KERNEL); + if (!tmp) + goto error; + do { + token = strsep(&buf, "\n"); + if (token == NULL || strlen(token) == 0) + break; + memset(tmp, 0, buf_len); + strncpy(tmp, token, strlen(token)); + ap = extract_ap_from_file(tmp); + if (!ap) + goto error; + if (total_configured_ap_num != ap->index || + ap->index > MAX_AP_NUM) { + pr_err("%s - Invalid index found\n", __func__); + goto error; + } + if (ap->index < MAX_AP_NUM) { + ap_list[ap->index] = ap; + total_configured_ap_num++; + } + } while (1); + ret = true; +error: + kfree(buf); + kfree(tmp); + if (fw_ap_config_entry) + release_firmware(fw_ap_config_entry); + return ret; +} + +int load_simulation_data(struct device *dev) +{ + return read_ap_config(dev) && read_scan_config(dev); +} + +void data_clean_up(void) +{ + int i; + + for (i = 0; i < total_configured_scan_result; i++) { + free_scan_ap_info_list(scan_list[i]->scanList); + kfree(scan_list[i]->scanList); // free list head + kfree(scan_list[i]); + } + memset(ap_list, 0, MAX_AP_NUM * sizeof(struct access_point *)); + memset(scan_list, 0, MAX_SCAN_CONFIG * sizeof(struct scan_config *)); + total_configured_ap_num = 0; + total_configured_scan_result = 0; +} + +struct access_point **get_ap_list(int *list_len_ptr) +{ + *list_len_ptr = total_configured_ap_num; + return ap_list; +} + +struct scan_config **get_scan_config_list(int *list_len_ptr, + char *switch_factor_ptr) +{ + *list_len_ptr = total_configured_scan_result; + *switch_factor_ptr = scan_result_switch_factor; + return scan_list; +} + diff --git a/wlan_simulation/virt_wifi_data.h b/wlan_simulation/virt_wifi_data.h new file mode 100644 index 0000000..6270523 --- /dev/null +++ b/wlan_simulation/virt_wifi_data.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* virt_wifi_data.h + * + * Load simulation data from the file. + * + * Copyright (C) 2019 Google LLC + * + * Author: lesl@google.com + */ +#ifndef __VIRT_WIFI_DATA_H +#define __VIRT_WIFI_DATA_H + +#include <linux/firmware.h> + +#define MAX_AP_NUM 100 +#define MAX_SCAN_CONFIG 100 +#define AP_LIST_CONFIG_FILE "cf_ap_list" +#define SCAN_CONTROL_CONFIG_FILE "cf_scan_control_list" + +// Each scan config format is index(max len=2), rssi(max len=4); +#define MAX_AP_SCAN_CONFIG_LEN 8 +// The value of max control setting is 99999 +#define MAX_CONTROL_SETTING_LEN 5 + +int load_simulation_data(struct device *dev); +struct access_point **get_ap_list(int *len); +struct scan_config **get_scan_config_list(int *leni, char *switch_factor); +void data_clean_up(void); + +#endif diff --git a/wlan_simulation/virt_wifi_simulation.c b/wlan_simulation/virt_wifi_simulation.c new file mode 100644 index 0000000..42b8b50 --- /dev/null +++ b/wlan_simulation/virt_wifi_simulation.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +/* virt_wifi_simulation.c + * + * Regist ops to virt_wifi driver. + * + * And decide which simulation data need to simulate. + * + * Copyright (C) 2019 Google LLC + * + * Author: lesl@google.com + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/slab.h> +#include <net/cfg80211.h> +#include <net/virt_wifi.h> +#include "virt_wifi_simulation.h" +#include "virt_wifi_data.h" + +static struct virt_wifi_network_simulation ops = { + .notify_device_open = notify_device_open, + .notify_device_stop = notify_device_stop, + .notify_scan_trigger = notify_scan_trigger, + .generate_virt_scan_result = generate_virt_scan_result, +}; + +struct device wlan_simulation_device; + +struct information_element { + u8 tag; + u8 len; + u8 *data; +} __packed; + +char scan_result_switch_factor; +int total_configured_ap_num; +int total_configured_scan_result; +int current_scan_trigger_count; +u64 current_scan_trigger_time; +u64 wifi_enable_tsf; +int last_scan_config_index; +struct access_point **ap_list; +struct scan_config **scan_list; + +static u8 *convert_bssid(char *bssid_str) +{ + char *token, *tmp; + unsigned long val; + int parser_index = 0; + u8 *converted_bssid = kzalloc(ETH_ALEN, GFP_KERNEL); + + if (!converted_bssid) + return NULL; + + tmp = kstrdup(bssid_str, GFP_KERNEL); + if (!tmp) { + kfree(converted_bssid); + return NULL; + } + + do { + token = strsep(&tmp, ":"); + if (token != NULL) { + kstrtoul(token, 16, &val); + converted_bssid[parser_index] = val; + parser_index++; + if (parser_index == ETH_ALEN) + break; + } + } while (token != NULL); + return converted_bssid; +} + +static u8 *generate_ie(struct access_point *ap, int *ie_len_ptr) +{ + int ssid_len; + u8 *ie = NULL; + char rsn_data_aes_psk[20] = {0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, + 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, + 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, + 0x0c, 0x00}; + struct information_element *ssid = + kzalloc(sizeof(struct information_element), GFP_KERNEL); + struct information_element *rsn = NULL; + + if (!ssid) + goto error; + ssid_len = strlen(ap->ssid); + ssid->tag = WLAN_EID_SSID; + ssid->len = ssid_len; + + if (!strcmp(ap->security_type, TYPE_WPA2)) { + pr_debug("ap : %s is WPA2", ap->ssid); + rsn = kzalloc(sizeof(struct information_element), GFP_KERNEL); + if (!rsn) + goto error; + rsn->tag = WLAN_EID_RSN; + rsn->len = 20; + } + *ie_len_ptr = ssid->len + 2; + if (rsn) + *ie_len_ptr += (rsn->len + 2); + + ie = kzalloc(*ie_len_ptr, GFP_KERNEL); + if (ie) { + memcpy(ie, ssid, 2); + memcpy(ie+2, ap->ssid, ssid_len); + } + if (rsn && ie) { + memcpy(ie + ssid_len + 2, rsn, 2); + memcpy(ie + ssid_len + 4, rsn_data_aes_psk, rsn->len); + } +error: + kfree(rsn); + kfree(ssid); + return ie; +} + +static int select_scan_config(void) +{ + int index; + u64 delta_time = (current_scan_trigger_time - wifi_enable_tsf) / + 1000000000; + + for (index = last_scan_config_index; + index < total_configured_scan_result; index++) { + if (scan_result_switch_factor == 'C' && + (scan_list[index]->control_setting > + current_scan_trigger_count)) { + break; + } + if (scan_result_switch_factor == 'T' && + scan_list[index]->control_setting > delta_time) { + break; + } + } + if (index == total_configured_scan_result) + index = total_configured_scan_result - 1; + if (last_scan_config_index != index) { + last_scan_config_index = index; + pr_info("%s switch config to %d", __func__, index); + } + return index; +} + +int get_virt_scan_result(struct wiphy *wiphy) +{ + int ie_len, ret = 0; + int targer_scan_config = select_scan_config(); + struct list_head *pos; + struct cfg80211_bss *informed_bss; + struct ieee80211_channel *channel; + u8 *bssid, *ie; + + list_for_each(pos, scan_list[targer_scan_config]->scanList) { + struct scan_ap_info *ap_info = + list_entry(pos, struct scan_ap_info, list); + ie_len = 0; + if (ap_info->ap_index > total_configured_ap_num) { + pr_err("The ap_index %d doesn't exist in cf_ap_list", + ap_info->ap_index); + ret = -1; + break; + } + channel = + ieee80211_get_channel(wiphy, + ap_list[ap_info->ap_index]->channel); + bssid = convert_bssid(ap_list[ap_info->ap_index]->bssid); + if (!bssid) { + ret = -1; + goto error; + } + ie = generate_ie(ap_list[ap_info->ap_index], &ie_len); + if (!ie) { + kfree(bssid); + ret = -1; + goto error; + } + informed_bss = cfg80211_inform_bss(wiphy, channel, + CFG80211_BSS_FTYPE_PRESP, + bssid, + ktime_get_ns(), + WLAN_CAPABILITY_ESS, 0, + (void *)ie, ie_len, + DBM_TO_MBM(ap_info->signal), + GFP_KERNEL); + cfg80211_put_bss(wiphy, informed_bss); + kfree(ie); + kfree(bssid); + ie = NULL; + bssid = NULL; + } +error: + return ret; +} + +int do_virt_scan(void) +{ + current_scan_trigger_count++; + current_scan_trigger_time = ktime_get_ns(); + pr_info("%s enter, count = %d, trigger time is |%lu|", + __func__, current_scan_trigger_count, + current_scan_trigger_time); + return 0; +} + +int virt_wifi_simulation_clean_up(void) +{ + pr_info("%s enter", __func__); + total_configured_ap_num = 0; + total_configured_scan_result = 0; + current_scan_trigger_count = 0; + current_scan_trigger_time = 0; + wifi_enable_tsf = 0; + last_scan_config_index = 0; + data_clean_up(); + return 0; +} + +void notify_device_open(struct net_device *dev) +{ + if (!load_simulation_data(&wlan_simulation_device)) { + virt_wifi_simulation_clean_up(); + return; + } + ap_list = get_ap_list(&total_configured_ap_num); + scan_list = get_scan_config_list(&total_configured_scan_result, + &scan_result_switch_factor); + wifi_enable_tsf = ktime_get_ns(); + pr_info("%s - total ap num=%d and total scan config num = %d,", + __func__, total_configured_ap_num, + total_configured_scan_result); + pr_info(" %s - switch factor = %c and enable time :|%lu|", + __func__, scan_result_switch_factor, wifi_enable_tsf); +} + +void notify_device_stop(struct net_device *dev) +{ + virt_wifi_unregister_network_simulation(); + virt_wifi_simulation_clean_up(); + virt_wifi_register_network_simulation(&ops); +} + +void notify_scan_trigger(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + do_virt_scan(); +} + +int generate_virt_scan_result(struct wiphy *wiphy) +{ + if ((total_configured_ap_num && total_configured_scan_result)) + get_virt_scan_result(wiphy); + return 0; +} + +int __init init_virt_data_simulation_module(void) +{ + pr_info("%s - enter", __func__); + virt_wifi_register_network_simulation(&ops); + device_register(&wlan_simulation_device); + return 0; +} + +void __exit exit_virt_data_simulation_module(void) +{ + pr_info("%s - enter", __func__); + device_unregister(&wlan_simulation_device); + virt_wifi_simulation_clean_up(); + virt_wifi_unregister_network_simulation(); +} + +module_init(init_virt_data_simulation_module); +module_exit(exit_virt_data_simulation_module); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Les Lee <lesl@google.com>"); +MODULE_DESCRIPTION("Module for the wifi virt driver data simulation."); + diff --git a/wlan_simulation/virt_wifi_simulation.h b/wlan_simulation/virt_wifi_simulation.h new file mode 100644 index 0000000..12e9b71 --- /dev/null +++ b/wlan_simulation/virt_wifi_simulation.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* virt_wifi_simulation.h + * + * Register ops to virt_wifi driver. + * + * And decide which simulation data need to simulate. + * + * Copyright (C) 2019 Google LLC + * + * Author: lesl@google.com + */ +#ifndef __VIRT_WIFI_SIMULATION_H +#define __VIRT_WIFI_SIMULATION_H + +#include <net/cfg80211.h> + +#define BSSID_LEN 17 +#define MAX_SSID_LEN 32 +#define MAX_SECURITY_TYPE_LEN 4 +#define TYPE_WPA2 "WPA2" + +struct access_point { + uint8_t index; + char bssid[BSSID_LEN + 1]; + char security_type[MAX_SECURITY_TYPE_LEN + 1]; + int32_t channel; + char ssid[MAX_SSID_LEN + 1]; +}; + +struct scan_ap_info { + uint8_t ap_index; + int32_t signal; + struct list_head list; +}; + +struct scan_config { + int32_t control_setting; + struct list_head *scanList; +}; + +void notify_device_open(struct net_device *dev); +void notify_device_stop(struct net_device *dev); +void notify_scan_trigger(struct wiphy *wiphy, + struct cfg80211_scan_request *req); +int generate_virt_scan_result(struct wiphy *wiphy); + +#endif |