blob: 5c892f137f450766850bd7842e44e5eb6e9220ee [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2020 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import selenium
import time
from acts_contrib.test_utils.wifi.wifi_retail_ap.netgear_r7500 import NetgearR7500AP
from acts_contrib.test_utils.wifi.wifi_retail_ap import BlockingBrowser
BROWSER_WAIT_SHORT = 1
BROWSER_WAIT_MED = 3
BROWSER_WAIT_LONG = 30
BROWSER_WAIT_EXTRA_LONG = 60
class NetgearRAX120AP(NetgearR7500AP):
"""Class that implements Netgear RAX120 AP.
Since most of the class' implementation is shared with the R7500, this
class inherits from NetgearR7500AP and simply redefines config parameters
"""
def init_gui_data(self):
"""Function to initialize data used while interacting with web GUI"""
self.config_page = ('{protocol}://{username}:{password}@'
'{ip_address}:{port}/index.htm').format(
protocol=self.ap_settings['protocol'],
username=self.ap_settings['admin_username'],
password=self.ap_settings['admin_password'],
ip_address=self.ap_settings['ip_address'],
port=self.ap_settings['port'])
self.config_page_advanced = (
'{protocol}://{username}:{password}@'
'{ip_address}:{port}/adv_index.htm').format(
protocol=self.ap_settings['protocol'],
username=self.ap_settings['admin_username'],
password=self.ap_settings['admin_password'],
ip_address=self.ap_settings['ip_address'],
port=self.ap_settings['port'])
self.capabilities = {
'interfaces': ['2G', '5G_1'],
'channels': {
'2G': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
'5G_1': [
36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116,
120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165
]
},
'modes': {
'2G': ['VHT20', 'VHT40', 'HE20', 'HE40'],
'5G_1': [
'VHT20', 'VHT40', 'VHT80', 'VHT160', 'HE20', 'HE40',
'HE80', 'HE160'
]
},
'default_mode': 'HE'
}
for interface in self.capabilities['interfaces']:
self.ap_settings[interface] = {}
self.config_page_fields = {
'region': 'WRegion',
'enable_ax': 'enable_ax_chec',
('2G', 'status'): 'enable_ap',
('5G_1', 'status'): 'enable_ap_an',
('2G', 'ssid'): 'ssid',
('5G_1', 'ssid'): 'ssid_an',
('2G', 'channel'): 'w_channel',
('5G_1', 'channel'): 'w_channel_an',
('2G', 'bandwidth'): 'opmode',
('5G_1', 'bandwidth'): 'opmode_an',
('2G', 'security_type'): 'security_type',
('5G_1', 'security_type'): 'security_type_an',
('2G', 'password'): 'passphrase',
('5G_1', 'password'): 'passphrase_an'
}
self.region_map = {
'0': 'Africa',
'1': 'Asia',
'2': 'Australia',
'3': 'Canada',
'4': 'Europe',
'5': 'Israel',
'6': 'Japan',
'7': 'Korea',
'8': 'Mexico',
'9': 'South America',
'10': 'United States',
'11': 'China',
'12': 'India',
'13': 'Malaysia',
'14': 'Middle East(Algeria/Syria/Yemen)',
'15': 'Middle East(Iran/Labanon/Qatar)',
'16': 'Middle East(Egypt/Tunisia/Kuwait)',
'17': 'Middle East(Turkey)',
'18': 'Middle East(Saudi Arabia/United Arab Emirates)',
'19': 'Russia',
'20': 'Singapore',
'21': 'Taiwan',
'Australia': 'Australia',
'Europe': 'Europe',
'Korea': 'Korea',
'Singapore': 'Singapore',
'Hong Kong': 'Hong Kong',
'United States': 'United States',
}
self.bw_mode_text = {
'2G': {
'11g': 'Up to 54 Mbps (11g)',
'HE20': 'Up to 573.5 Mbps (11ax, HT20, 1024-QAM)',
'HE40': 'Up to 1147 Mbps (11ax, HT40, 1024-QAM)',
'VHT20': 'Up to 481 Mbps (11ng, HT20, 1024-QAM)',
'VHT40': 'Up to 1000 Mbps (11ng, HT40, 1024-QAM)'
},
'5G_1': {
'HE20': 'Up to 1147 Mbps (11ax, HT20, 1024-QAM)',
'HE40': 'Up to 2294 Mbps (11ax, HT40, 1024-QAM)',
'HE80': 'Up to 4803 Mbps (80MHz) (11ax, HT80, 1024-QAM)',
'HE160': 'Up to 4803 Mbps (160MHz) (11ax, HT160, 1024-QAM)',
'VHT20': 'Up to 962 Mbps (11ac, HT20, 1024-QAM)',
'VHT40': 'Up to 2000 Mbps (11ac, HT40, 1024-QAM)',
'VHT80': 'Up to 4333 Mbps (80MHz) (11ac, HT80, 1024-QAM)',
'VHT160': 'Up to 4333 Mbps (160MHz) (11ac, HT160, 1024-QAM)'
}
}
self.bw_mode_values = {
# first key is a boolean indicating if 11ax is enabled
0: {
'1': '11g',
'2': 'VHT20',
'3': 'VHT40',
'7': 'VHT20',
'8': 'VHT40',
'9': 'VHT80',
'10': 'VHT160'
},
1: {
'1': '11g',
'2': 'HE20',
'3': 'HE40',
'7': 'HE20',
'8': 'HE40',
'9': 'HE80',
'10': 'HE160',
'54': '11g',
'573.5': 'HE20',
'1146': 'HE40',
'1147': 'HE20',
'2294': 'HE40',
'4803-HT80': 'HE80',
'4803-HT160': 'HE160'
}
}
self.security_mode_values = {
'2G': {
'Disable': 'security_disable',
'WPA2-PSK': 'security_wpa2'
},
'5G_1': {
'Disable': 'security_an_disable',
'WPA2-PSK': 'security_an_wpa2'
}
}
def _set_channel_and_bandwidth(self,
network,
channel=None,
bandwidth=None):
"""Helper function that sets network bandwidth and channel.
Args:
network: string containing network identifier (2G, 5G_1, 5G_2)
channel: desired channel
bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
"""
setting_to_update = {network: {}}
if channel:
if channel not in self.capabilities['channels'][network]:
raise RuntimeError('Ch{} is not supported on {} interface.'.format(
channel, network))
setting_to_update[network]['channel'] = channel
if bandwidth is None:
return setting_to_update
if 'bw' in bandwidth:
bandwidth = bandwidth.replace('bw',
self.capabilities['default_mode'])
if bandwidth not in self.capabilities['modes'][network]:
raise RuntimeError('{} mode is not supported on {} interface.'.format(
bandwidth, network))
setting_to_update[network]['bandwidth'] = str(bandwidth)
setting_to_update['enable_ax'] = int('HE' in bandwidth)
# Check if other interfaces need to be changed too
requested_mode = 'HE' if 'HE' in bandwidth else 'VHT'
for other_network in self.capabilities['interfaces']:
if other_network == network:
continue
other_mode = 'HE' if 'HE' in self.ap_settings[other_network][
'bandwidth'] else 'VHT'
other_bw = ''.join([
x for x in self.ap_settings[other_network]['bandwidth']
if x.isdigit()
])
if other_mode != requested_mode:
updated_mode = '{}{}'.format(requested_mode, other_bw)
self.log.warning('All networks must be VHT or HE. '
'Updating {} to {}'.format(
other_network, updated_mode))
setting_to_update.setdefault(other_network, {})
setting_to_update[other_network]['bandwidth'] = updated_mode
return setting_to_update
def set_bandwidth(self, network, bandwidth):
"""Function that sets network bandwidth/mode.
Args:
network: string containing network identifier (2G, 5G_1, 5G_2)
bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
"""
setting_to_update = self._set_channel_and_bandwidth(
network, bandwidth=bandwidth)
self.update_ap_settings(setting_to_update)
def set_channel(self, network, channel):
"""Function that sets network channel.
Args:
network: string containing network identifier (2G, 5G_1, 5G_2)
channel: string or int containing channel
"""
setting_to_update = self._set_channel_and_bandwidth(network,
channel=channel)
self.update_ap_settings(setting_to_update)
def set_channel_and_bandwidth(self, network, channel, bandwidth):
"""Function that sets network bandwidth/mode.
Args:
network: string containing network identifier (2G, 5G_1, 5G_2)
channel: desired channel
bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
"""
setting_to_update = self._set_channel_and_bandwidth(
network, channel=channel, bandwidth=bandwidth)
self.update_ap_settings(setting_to_update)
def read_ap_settings(self):
"""Function to read ap wireless settings."""
# Get radio status (on/off)
self.read_radio_on_off()
# Get radio configuration. Note that if both radios are off, the below
# code will result in an error
with BlockingBrowser(self.ap_settings['headless_browser'],
900) as browser:
browser.visit_persistent(self.config_page,
BROWSER_WAIT_MED,
10,
check_for_element='wireless')
wireless_button = browser.find_by_id('wireless').first
wireless_button.click()
time.sleep(BROWSER_WAIT_MED)
with browser.get_iframe('formframe') as iframe:
# read if 11ax is enabled first
config_item = iframe.find_by_name('enable_ax').first
self.ap_settings['enable_ax'] = int(config_item.checked)
# read rest of configuration
for key, value in self.config_page_fields.items():
if 'bandwidth' in key:
config_item = iframe.find_by_name(value).first
self.ap_settings[key[0]][key[1]] = self.bw_mode_values[
self.ap_settings['enable_ax']][config_item.value]
elif 'region' in key:
config_item = iframe.find_by_name(value).first
self.ap_settings['region'] = self.region_map[
config_item.value]
elif 'password' in key:
try:
config_item = iframe.find_by_name(value).first
self.ap_settings[key[0]][
key[1]] = config_item.value
self.ap_settings[
key[0]]['security_type'] = 'WPA2-PSK'
except:
self.ap_settings[key[0]][
key[1]] = 'defaultpassword'
self.ap_settings[
key[0]]['security_type'] = 'Disable'
elif ('ssid' in key):
config_item = iframe.find_by_name(value).first
self.ap_settings[key[0]][key[1]] = config_item.value
elif ('channel' in key):
config_item = iframe.find_by_name(value).first
self.ap_settings[key[0]][key[1]] = int(
config_item.value)
return self.ap_settings.copy()
def configure_ap(self, **config_flags):
"""Function to configure ap wireless settings."""
# Turn radios on or off
if config_flags['status_toggled']:
self.configure_radio_on_off()
# Configure radios
with BlockingBrowser(self.ap_settings['headless_browser'],
900) as browser:
browser.visit_persistent(self.config_page,
BROWSER_WAIT_MED,
10,
check_for_element='wireless')
wireless_button = browser.find_by_id('wireless').first
wireless_button.click()
time.sleep(BROWSER_WAIT_MED)
with browser.get_iframe('formframe') as iframe:
# Create action chain
action = selenium.webdriver.common.action_chains.ActionChains(
browser.driver)
# Configure 11ax on or off
curr_ax_enabled = int(
iframe.find_by_name('enable_ax').first.checked)
if self.ap_settings['enable_ax'] != curr_ax_enabled:
ax_checkbox = browser.driver.find_element_by_id(
'enable_ax_chec')
action.move_to_element(ax_checkbox).click().perform()
# Update AP region. Must be done before channel setting
try:
config_item = iframe.find_by_name(
self.config_page_fields['region']).first
config_item.select_by_text(self.ap_settings['region'])
except:
self.log.warning('Could not set AP region to {}.'.format(
self.ap_settings['region']))
# Update wireless settings for each network
for key, value in self.config_page_fields.items():
if 'ssid' in key:
config_item = iframe.find_by_name(value).first
config_item.fill(self.ap_settings[key[0]][key[1]])
elif 'channel' in key:
channel = self.ap_settings[key[0]][key[1]]
if int(channel) < 10:
channel_string = '0' + str(channel)
elif int(channel) > 48 and int(channel) < 149:
channel_string = str(channel) + 'DFS'
else:
channel_string = str(channel)
config_item = iframe.find_by_name(value).first
try:
config_item.select_by_text(channel_string)
except AttributeError:
self.log.warning(
'Cannot select channel. Keeping AP default.')
elif 'bandwidth' in key:
config_item = iframe.find_by_name(value).first
try:
config_item.select_by_text(
str(self.bw_mode_text[key[0]][self.ap_settings[
key[0]][key[1]]]))
except AttributeError:
self.log.warning(
'Cannot select bandwidth. Keeping AP default.')
# Update passwords for WPA2-PSK protected networks
# (Must be done after security type is selected)
for key, value in self.config_page_fields.items():
if 'security_type' in key:
security_option = browser.driver.find_element_by_id(
self.security_mode_values[key[0]][self.ap_settings[
key[0]][key[1]]])
action = selenium.webdriver.common.action_chains.ActionChains(
browser.driver)
action.move_to_element(
security_option).click().perform()
if self.ap_settings[key[0]][key[1]] == 'WPA2-PSK':
config_item = iframe.find_by_name(
self.config_page_fields[(key[0],
'password')]).first
config_item.fill(
self.ap_settings[key[0]]['password'])
apply_button = iframe.find_by_name('Apply')
apply_button[0].click()
time.sleep(BROWSER_WAIT_SHORT)
try:
alert = browser.get_alert()
alert.accept()
except:
pass
time.sleep(BROWSER_WAIT_SHORT)
try:
alert = browser.get_alert()
alert.accept()
except:
pass
time.sleep(BROWSER_WAIT_SHORT)
time.sleep(BROWSER_WAIT_EXTRA_LONG)
browser.visit_persistent(self.config_page, BROWSER_WAIT_EXTRA_LONG,
10)