diff options
author | Girish Moturu <gmoturu@google.com> | 2020-09-22 09:10:48 -0700 |
---|---|---|
committer | Girish Moturu <gmoturu@google.com> | 2020-09-24 21:32:46 +0000 |
commit | 3175865361c7a324510b2a2e690a00d326ba4d17 (patch) | |
tree | 64c58ffd747bf900e7c0d4441f43f9e5f2227aec | |
parent | 2687dd1abaab36c9eefd8da586935f4ccc533fc2 (diff) | |
download | platform_tools_test_connectivity-3175865361c7a324510b2a2e690a00d326ba4d17.tar.gz platform_tools_test_connectivity-3175865361c7a324510b2a2e690a00d326ba4d17.tar.bz2 platform_tools_test_connectivity-3175865361c7a324510b2a2e690a00d326ba4d17.zip |
[OpenWrt] Openwrt support for WiFi.
Cherry picked changes from git_master
Bug: 158349179
Test: Verified the changes
Merged-In: If7031da9fe0607f1035c6617b1f292b3668913cd
Change-Id: I7fa44fedfb87591fd06c41f56dc3728e15bcaf07
Exempt-From-Owner-Approval: Changes approved in internal master
-rw-r--r-- | acts/framework/acts/controllers/__init__.py | 2 | ||||
-rw-r--r-- | acts/framework/acts/controllers/openwrt_ap.py | 253 | ||||
-rw-r--r-- | acts/framework/acts/controllers/openwrt_lib/__init__.py | 0 | ||||
-rw-r--r-- | acts/framework/acts/controllers/openwrt_lib/wireless_config.py | 50 | ||||
-rw-r--r-- | acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py | 124 | ||||
-rw-r--r-- | acts/framework/acts/keys.py | 5 | ||||
-rw-r--r-- | acts/framework/acts/test_utils/wifi/WifiBaseTest.py | 106 |
7 files changed, 538 insertions, 2 deletions
diff --git a/acts/framework/acts/controllers/__init__.py b/acts/framework/acts/controllers/__init__.py index 1c8ed4ca00..b805e9e206 100644 --- a/acts/framework/acts/controllers/__init__.py +++ b/acts/framework/acts/controllers/__init__.py @@ -26,5 +26,5 @@ def destroy(objs): __all__ = [ "android_device", "attenuator", "bluetooth_pts_device", "monsoon", "access_point", "iperf_server", "packet_sender", "arduino_wifi_dongle", - "packet_capture", "fuchsia_device", "pdu" + "packet_capture", "fuchsia_device", "pdu", "openwrt_ap" ] diff --git a/acts/framework/acts/controllers/openwrt_ap.py b/acts/framework/acts/controllers/openwrt_ap.py new file mode 100644 index 0000000000..05bd38c271 --- /dev/null +++ b/acts/framework/acts/controllers/openwrt_ap.py @@ -0,0 +1,253 @@ +"""Controller for Open WRT access point.""" + +import time + +from acts import logger +from acts.controllers.ap_lib import hostapd_constants +from acts.controllers.openwrt_lib import wireless_config +from acts.controllers.openwrt_lib import wireless_settings_applier +from acts.controllers.utils_lib.ssh import connection +from acts.controllers.utils_lib.ssh import settings + +MOBLY_CONTROLLER_CONFIG_NAME = "OpenWrtAP" +ACTS_CONTROLLER_REFERENCE_NAME = "access_points" +OPEN_SECURITY = "none" +PSK_SECURITY = "psk2" +WEP_SECURITY = "wep" +ENT_SECURITY = "wpa2" +ENABLE_RADIO = "0" +WIFI_2G = "wifi2g" +WIFI_5G = "wifi5g" + + +def create(configs): + """Creates ap controllers from a json config. + + Creates an ap controller from either a list, or a single element. The element + can either be just the hostname or a dictionary containing the hostname and + username of the AP to connect to over SSH. + + Args: + configs: The json configs that represent this controller. + + Returns: + AccessPoint object + + Example: + Below is the config file entry for OpenWrtAP as a list. A testbed can have + 1 or more APs to configure. Each AP has a "ssh_config" key to provide SSH + login information. OpenWrtAP#__init__() uses this to create SSH object. + + "OpenWrtAP": [ + { + "ssh_config": { + "user" : "root", + "host" : "192.168.1.1" + } + }, + { + "ssh_config": { + "user" : "root", + "host" : "192.168.1.2" + } + } + ] + """ + return [OpenWrtAP(c) for c in configs] + + +def destroy(aps): + """Destroys a list of AccessPoints. + + Args: + aps: The list of AccessPoints to destroy. + """ + for ap in aps: + ap.close() + ap.close_ssh() + + +def get_info(aps): + """Get information on a list of access points. + + Args: + aps: A list of AccessPoints. + + Returns: + A list of all aps hostname. + """ + return [ap.ssh_settings.hostname for ap in aps] + + +class OpenWrtAP(object): + """An AccessPoint controller. + + Attributes: + log: Logging object for AccessPoint. + ssh: The ssh connection to the AP. + ssh_settings: The ssh settings being used by the ssh connection. + wireless_setting: object holding wireless configuration. + """ + + def __init__(self, config): + """Initialize AP.""" + self.ssh_settings = settings.from_config(config["ssh_config"]) + self.ssh = connection.SshConnection(self.ssh_settings) + self.log = logger.create_logger( + lambda msg: "[OpenWrtAP|%s] %s" % (self.ssh_settings.hostname, msg)) + self.wireless_setting = None + + def configure_ap(self, wifi_configs, channel_2g, channel_5g): + """Configure AP with the required settings. + + Each test class inherits WifiBaseTest. Based on the test, we may need to + configure PSK, WEP, OPEN, ENT networks on 2G and 5G bands in any + combination. We call WifiBaseTest methods get_psk_network(), + get_open_network(), get_wep_network() and get_ent_network() to create + dictionaries which contains this information. 'wifi_configs' is a list of + such dictionaries. Example below configures 2 WiFi networks - 1 PSK 2G and + 1 Open 5G on one AP. configure_ap() is called from WifiBaseTest to + configure the APs. + + wifi_configs = [ + { + '2g': { + 'SSID': '2g_AkqXWPK4', + 'security': 'psk2', + 'password': 'YgYuXqDO9H', + 'hiddenSSID': False + }, + }, + { + '5g': { + 'SSID': '5g_8IcMR1Sg', + 'security': 'none', + 'hiddenSSID': False + }, + } + ] + + Args: + wifi_configs: list of network settings for 2G and 5G bands. + channel_2g: channel for 2G band. + channel_5g: channel for 5G band. + """ + # generate wifi configs to configure + wireless_configs = self.generate_wireless_configs(wifi_configs) + self.wireless_setting = wireless_settings_applier.WirelessSettingsApplier( + self.ssh, wireless_configs, channel_2g, channel_5g) + self.wireless_setting.apply_wireless_settings() + + def start_ap(self): + """Starts the AP with the settings in /etc/config/wireless.""" + self.ssh.run("wifi up") + time.sleep(9) # wait for sometime for AP to come up + + def stop_ap(self): + """Stops the AP.""" + self.ssh.run("wifi down") + time.sleep(9) # wait for sometime for AP to go down + + def generate_wireless_configs(self, wifi_configs): + """Generate wireless configs to configure. + + Converts wifi_configs from configure_ap() to a list of 'WirelessConfig' + objects. Each object represents a wifi network to configure on the AP. + + Args: + wifi_configs: Network list of different security types and bands. + + Returns: + wireless configuration for openwrt AP. + """ + num_2g = 1 + num_5g = 1 + wireless_configs = [] + + for i in range(len(wifi_configs)): + if hostapd_constants.BAND_2G in wifi_configs[i]: + config = wifi_configs[i][hostapd_constants.BAND_2G] + if config["security"] == PSK_SECURITY: + wireless_configs.append( + wireless_config.WirelessConfig("%s%s" % (WIFI_2G, num_2g), + config["SSID"], + config["security"], + hostapd_constants.BAND_2G, + password=config["password"], + hidden=config["hiddenSSID"])) + elif config["security"] == WEP_SECURITY: + wireless_configs.append( + wireless_config.WirelessConfig("%s%s" % (WIFI_2G, num_2g), + config["SSID"], + config["security"], + hostapd_constants.BAND_2G, + wep_key=config["wepKeys"][0], + hidden=config["hiddenSSID"])) + elif config["security"] == OPEN_SECURITY: + wireless_configs.append( + wireless_config.WirelessConfig("%s%s" % (WIFI_2G, num_2g), + config["SSID"], + config["security"], + hostapd_constants.BAND_2G, + hidden=config["hiddenSSID"])) + elif config["security"] == ENT_SECURITY: + wireless_configs.append( + wireless_config.WirelessConfig( + "%s%s" % (WIFI_2G, num_2g), + config["SSID"], + config["security"], + hostapd_constants.BAND_2G, + radius_server_ip=config["radius_server_ip"], + radius_server_port=config["radius_server_port"], + radius_server_secret=config["radius_server_secret"], + hidden=config["hiddenSSID"])) + num_2g += 1 + if hostapd_constants.BAND_5G in wifi_configs[i]: + config = wifi_configs[i][hostapd_constants.BAND_5G] + if config["security"] == PSK_SECURITY: + wireless_configs.append( + wireless_config.WirelessConfig("%s%s" % (WIFI_5G, num_5g), + config["SSID"], + config["security"], + hostapd_constants.BAND_5G, + password=config["password"], + hidden=config["hiddenSSID"])) + elif config["security"] == WEP_SECURITY: + wireless_configs.append( + wireless_config.WirelessConfig("%s%s" % (WIFI_5G, num_5g), + config["SSID"], + config["security"], + hostapd_constants.BAND_5G, + wep_key=config["wepKeys"][0], + hidden=config["hiddenSSID"])) + elif config["security"] == OPEN_SECURITY: + wireless_configs.append( + wireless_config.WirelessConfig("%s%s" % (WIFI_5G, num_5g), + config["SSID"], + config["security"], + hostapd_constants.BAND_5G, + hidden=config["hiddenSSID"])) + elif config["security"] == ENT_SECURITY: + wireless_configs.append( + wireless_config.WirelessConfig( + "%s%s" % (WIFI_5G, num_5g), + config["SSID"], + config["security"], + hostapd_constants.BAND_5G, + radius_server_ip=config["radius_server_ip"], + radius_server_port=config["radius_server_port"], + radius_server_secret=config["radius_server_secret"], + hidden=config["hiddenSSID"])) + num_5g += 1 + + return wireless_configs + + def close(self): + """Reset wireless settings to default and stop AP.""" + if self.wireless_setting: + self.wireless_setting.cleanup_wireless_settings() + + def close_ssh(self): + """Close SSH connection to AP.""" + self.ssh.close() + diff --git a/acts/framework/acts/controllers/openwrt_lib/__init__.py b/acts/framework/acts/controllers/openwrt_lib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/acts/framework/acts/controllers/openwrt_lib/__init__.py diff --git a/acts/framework/acts/controllers/openwrt_lib/wireless_config.py b/acts/framework/acts/controllers/openwrt_lib/wireless_config.py new file mode 100644 index 0000000000..ea89636e2d --- /dev/null +++ b/acts/framework/acts/controllers/openwrt_lib/wireless_config.py @@ -0,0 +1,50 @@ +"""Class for Wireless config.""" + +NET_IFACE = "lan" + + +class WirelessConfig(object): + """Creates an object to hold wireless config. + + Attributes: + name: name of the wireless config + ssid: SSID of the network. + security: security of the wifi network. + band: band of the wifi network. + iface: network interface of the wifi network. + password: password for psk network. + wep_key: wep keys for wep network. + wep_key_num: key number for wep network. + radius_server_ip: IP address of radius server. + radius_server_port: Port number of radius server. + radius_server_secret: Secret key of radius server. + hidden: Boolean, if the wifi network is hidden. + """ + + def __init__( + self, + name, + ssid, + security, + band, + iface=NET_IFACE, + password=None, + wep_key=None, + wep_key_num=1, + radius_server_ip=None, + radius_server_port=None, + radius_server_secret=None, + hidden=False): + self.name = name + self.ssid = ssid + self.security = security + self.band = band + self.iface = iface + self.password = password + self.wep_key = wep_key + self.wep_key_num = wep_key_num + self.radius_server_ip = radius_server_ip + self.radius_server_port = radius_server_port + self.radius_server_secret = radius_server_secret + self.hidden = hidden + diff --git a/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py b/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py new file mode 100644 index 0000000000..cfb94d1503 --- /dev/null +++ b/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py @@ -0,0 +1,124 @@ +"""Class to configure wireless settings.""" + +import time +from acts.controllers.ap_lib import hostapd_constants + +LEASE_FILE = "/tmp/dhcp.leases" +DNSMASQ_RESTART = "/etc/init.d/dnsmasq restart" +OPEN_SECURITY = "none" +PSK_SECURITY = "psk2" +WEP_SECURITY = "wep" +ENT_SECURITY = "wpa2" +ENABLE_RADIO = "0" +DISABLE_RADIO = "1" +ENABLE_HIDDEN = "1" + + +class WirelessSettingsApplier(object): + """Class for wireless settings. + + Attributes: + ssh: ssh object for the AP. + wireless_configs: a list of + acts.controllers.openwrt_lib.wireless_config.WirelessConfig. + channel_2g: channel for 2G band. + channel_5g: channel for 5G band. + """ + + def __init__(self, ssh, configs, channel_2g, channel_5g): + """Initialize wireless settings. + + Args: + ssh: ssh connection object. + configs: a list of + acts.controllers.openwrt_lib.wireless_config.WirelessConfig. + channel_2g: channel for 2G band. + channel_5g: channel for 5G band. + """ + self.ssh = ssh + self.wireless_configs = configs + self.channel_2g = channel_2g + self.channel_5g = channel_5g + + def apply_wireless_settings(self): + """Configure wireless settings from a list of configs.""" + + # set channels for 2G and 5G bands + self.ssh.run("uci set wireless.radio1.channel='%s'" % self.channel_2g) + self.ssh.run("uci set wireless.radio0.channel='%s'" % self.channel_5g) + + # disable default OpenWrt SSID + self.ssh.run("uci set wireless.default_radio1.disabled='%s'" % + DISABLE_RADIO) + self.ssh.run("uci set wireless.default_radio0.disabled='%s'" % + DISABLE_RADIO) + + # Enable radios + self.ssh.run("uci set wireless.radio1.disabled='%s'" % ENABLE_RADIO) + self.ssh.run("uci set wireless.radio0.disabled='%s'" % ENABLE_RADIO) + + for config in self.wireless_configs: + + # configure open network + if config.security == OPEN_SECURITY: + if config.band == hostapd_constants.BAND_2G: + self.ssh.run("uci set wireless.default_radio1.ssid='%s'" % + config.ssid) + self.ssh.run("uci set wireless.default_radio1.disabled='%s'" % + ENABLE_RADIO) + if config.hidden: + self.ssh.run("uci set wireless.default_radio1.hidden='%s'" % + ENABLE_HIDDEN) + elif config.band == hostapd_constants.BAND_5G: + self.ssh.run("uci set wireless.default_radio0.ssid='%s'" % + config.ssid) + self.ssh.run("uci set wireless.default_radio0.disabled='%s'" % + ENABLE_RADIO) + if config.hidden: + self.ssh.run("uci set wireless.default_radio0.hidden='%s'" % + ENABLE_HIDDEN) + continue + + self.ssh.run("uci set wireless.%s='wifi-iface'" % config.name) + if config.band == hostapd_constants.BAND_2G: + self.ssh.run("uci set wireless.%s.device='radio1'" % config.name) + else: + self.ssh.run("uci set wireless.%s.device='radio0'" % config.name) + self.ssh.run("uci set wireless.%s.network='%s'" % + (config.name, config.iface)) + self.ssh.run("uci set wireless.%s.mode='ap'" % config.name) + self.ssh.run("uci set wireless.%s.ssid='%s'" % + (config.name, config.ssid)) + self.ssh.run("uci set wireless.%s.encryption='%s'" % + (config.name, config.security)) + if config.security == PSK_SECURITY: + self.ssh.run("uci set wireless.%s.key='%s'" % + (config.name, config.password)) + elif config.security == WEP_SECURITY: + self.ssh.run("uci set wireless.%s.key%s='%s'" % + (config.name, config.wep_key_num, config.wep_key)) + self.ssh.run("uci set wireless.%s.key='%s'" % + (config.name, config.wep_key_num)) + elif config.security == ENT_SECURITY: + self.ssh.run("uci set wireless.%s.auth_secret='%s'" % + (config.name, config.radius_server_secret)) + self.ssh.run("uci set wireless.%s.auth_server='%s'" % + (config.name, config.radius_server_ip)) + self.ssh.run("uci set wireless.%s.auth_port='%s'" % + (config.name, config.radius_server_port)) + if config.hidden: + self.ssh.run("uci set wireless.%s.hidden='%s'" % + (config.name, ENABLE_HIDDEN)) + + self.ssh.run("uci commit wireless") + self.ssh.run("cp %s %s.tmp" % (LEASE_FILE, LEASE_FILE)) + + def cleanup_wireless_settings(self): + """Reset wireless settings to default.""" + self.ssh.run("wifi down") + self.ssh.run("rm -f /etc/config/wireless") + self.ssh.run("wifi config") + self.ssh.run("cp %s.tmp %s" % (LEASE_FILE, LEASE_FILE)) + self.ssh.run(DNSMASQ_RESTART) + time.sleep(9) + diff --git a/acts/framework/acts/keys.py b/acts/framework/acts/keys.py index eae9a3bb14..ae8945682c 100644 --- a/acts/framework/acts/keys.py +++ b/acts/framework/acts/keys.py @@ -57,6 +57,7 @@ class Config(enum.Enum): key_arduino_wifi_dongle = 'ArduinoWifiDongle' key_packet_capture = 'PacketCapture' key_pdu = 'PduDevice' + key_openwrt_ap = 'OpenWrtAP' # Internal keys, used internally, not exposed to user's config files. ikey_user_param = 'user_params' ikey_testbed_name = 'testbed_name' @@ -81,6 +82,7 @@ class Config(enum.Enum): m_key_arduino_wifi_dongle = 'arduino_wifi_dongle' m_key_packet_capture = 'packet_capture' m_key_pdu = 'pdu' + m_key_openwrt_ap = 'openwrt_ap' # A list of keys whose values in configs should not be passed to test # classes without unpacking first. @@ -104,7 +106,8 @@ class Config(enum.Enum): key_chameleon_device, key_arduino_wifi_dongle, key_packet_capture, - key_pdu + key_pdu, + key_openwrt_ap, ] # Keys that are file or folder paths. diff --git a/acts/framework/acts/test_utils/wifi/WifiBaseTest.py b/acts/framework/acts/test_utils/wifi/WifiBaseTest.py index 122709f5f0..e79d03eda5 100644 --- a/acts/framework/acts/test_utils/wifi/WifiBaseTest.py +++ b/acts/framework/acts/test_utils/wifi/WifiBaseTest.py @@ -295,6 +295,112 @@ class WifiBaseTest(BaseTestClass): self.update_bssid(ap_instance, ap, network, hostapd_constants.BAND_2G) + def configure_openwrt_ap_and_start( + self, + channel_5g=hostapd_constants.AP_DEFAULT_CHANNEL_5G, + channel_2g=hostapd_constants.AP_DEFAULT_CHANNEL_2G, + ssid_length_2g=hostapd_constants.AP_SSID_LENGTH_2G, + passphrase_length_2g=hostapd_constants.AP_PASSPHRASE_LENGTH_2G, + ssid_length_5g=hostapd_constants.AP_SSID_LENGTH_5G, + passphrase_length_5g=hostapd_constants.AP_PASSPHRASE_LENGTH_5G, + mirror_ap=False, + hidden=False, + same_ssid=False, + open_network=False, + wpa_network=False, + wep_network=False, + ent_network=False, + ent_network_pwd=False, + radius_conf_2g=None, + radius_conf_5g=None, + radius_conf_pwd=None, + ap_count=1): + """Create, configure and start OpenWrt AP. + + Args: + channel_5g: 5G channel to configure. + channel_2g: 2G channel to configure. + ssid_length_2g: Int, number of characters to use for 2G SSID. + passphrase_length_2g: Int, length of password for 2G network. + ssid_length_5g: Int, number of characters to use for 5G SSID. + passphrase_length_5g: Int, length of password for 5G network. + same_ssid: Boolean, determines if both bands on AP use the same SSID. + open_network: Boolean, to check if open network should be configured. + wpa_network: Boolean, to check if wpa network should be configured. + wep_network: Boolean, to check if wep network should be configured. + ent_network: Boolean, to check if ent network should be configured. + ent_network_pwd: Boolean, to check if ent pwd network should be configured. + radius_conf_2g: dictionary with enterprise radius server details. + radius_conf_5g: dictionary with enterprise radius server details. + radius_conf_pwd: dictionary with enterprise radiuse server details. + ap_count: APs to configure. + """ + self.reference_networks = [] + self.wpa_networks = [] + self.wep_networks = [] + self.ent_networks = [] + self.ent_networks_pwd = [] + self.open_network = [] + for _ in range(ap_count): + network_list = [] + if wpa_network: + wpa_dict = self.get_psk_network(mirror_ap, + self.reference_networks, + hidden, + same_ssid, + ssid_length_2g, + ssid_length_5g, + passphrase_length_2g, + passphrase_length_5g) + wpa_dict[hostapd_constants.BAND_2G]["security"] = "psk2" + wpa_dict[hostapd_constants.BAND_5G]["security"] = "psk2" + self.wpa_networks.append(wpa_dict) + network_list.append(wpa_dict) + if wep_network: + wep_dict = self.get_wep_network(mirror_ap, + self.wep_networks, + hidden, + same_ssid, + ssid_length_2g, + ssid_length_5g) + network_list.append(wep_dict) + if ent_network: + ent_dict = self.get_open_network(mirror_ap, + self.ent_networks, + hidden, + same_ssid, + ssid_length_2g, + ssid_length_5g) + ent_dict["2g"]["security"] = "wpa2" + ent_dict["2g"].update(radius_conf_2g) + ent_dict["5g"]["security"] = "wpa2" + ent_dict["5g"].update(radius_conf_5g) + network_list.append(ent_dict) + if ent_network_pwd: + ent_pwd_dict = self.get_open_network(mirror_ap, + self.ent_networks_pwd, + hidden, + same_ssid, + ssid_length_2g, + ssid_length_5g) + ent_pwd_dict["2g"]["security"] = "wpa2" + ent_pwd_dict["2g"].update(radius_conf_pwd) + ent_pwd_dict["5g"]["security"] = "wpa2" + ent_pwd_dict["5g"].update(radius_conf_pwd) + network_list.append(ent_pwd_dict) + if open_network: + open_dict = self.get_open_network(mirror_ap, + self.open_network, + hidden, + same_ssid, + ssid_length_2g, + ssid_length_5g) + network_list.append(open_dict) + self.access_points[_].configure_ap(network_list, + channel_2g, + channel_5g) + self.access_points[_].start_ap() + def legacy_configure_ap_and_start( self, channel_5g=hostapd_constants.AP_DEFAULT_CHANNEL_5G, |