summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlesl <lesl@google.com>2019-10-30 15:16:12 +0800
committerlesl <lesl@google.com>2019-12-13 14:27:48 +0800
commit311b8a6a3d8ee1ddd1afe28e8ccd07c1a6b55775 (patch)
tree5a85504f6180a2e2cb6763ea7b425643039778dc
parent675835ee5c8386e8942750829bca3dc4dd438788 (diff)
downloadcuttlefish-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/Kbuild2
-rw-r--r--wlan_simulation/Makefile6
-rw-r--r--wlan_simulation/virt_wifi_data.c295
-rw-r--r--wlan_simulation/virt_wifi_data.h30
-rw-r--r--wlan_simulation/virt_wifi_simulation.c282
-rw-r--r--wlan_simulation/virt_wifi_simulation.h47
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