Merge "Add Gale compatibility and enable 40 MHz mode"
Test: Done
Bug: 65563975
Change-Id: Ie1bc6607919a44621a86622da80bc3ec641bcede
(cherry picked from commit 7e7a65cdfebf09d07ef90ecbfba56900746693f6)
diff --git a/acts/framework/acts/controllers/access_point.py b/acts/framework/acts/controllers/access_point.py
index a8ea506..422e59f 100755
--- a/acts/framework/acts/controllers/access_point.py
+++ b/acts/framework/acts/controllers/access_point.py
@@ -16,7 +16,10 @@
import collections
import ipaddress
+import logging
+import time
+from acts.controllers.ap_lib import ap_get_interface
from acts.controllers.ap_lib import bridge_interface
from acts.controllers.ap_lib import dhcp_config
from acts.controllers.ap_lib import dhcp_server
@@ -27,9 +30,11 @@
from acts.controllers.utils_lib.commands import shell
from acts.controllers.utils_lib.ssh import connection
from acts.controllers.utils_lib.ssh import settings
+from acts.libs.proc import job
ACTS_CONTROLLER_CONFIG_NAME = 'AccessPoint'
ACTS_CONTROLLER_REFERENCE_NAME = 'access_points'
+_BRCTL = 'brctl'
def create(configs):
@@ -78,11 +83,6 @@
_ApInstance = collections.namedtuple('_ApInstance', ['hostapd', 'subnet'])
-# We use these today as part of a hardcoded mapping of interface name to
-# capabilities. However, medium term we need to start inspecting
-# interfaces to determine their capabilities.
-_AP_2GHZ_INTERFACE = 'wlan0'
-_AP_5GHZ_INTERFACE = 'wlan1'
# These ranges were split this way since each physical radio can have up
# to 8 SSIDs so for the 2GHz radio the DHCP range will be
# 192.168.1 - 8 and the 5Ghz radio will be 192.168.9 - 16
@@ -90,7 +90,6 @@
_AP_5GHZ_SUBNET_STR = '192.168.9.0/24'
_AP_2GHZ_SUBNET = dhcp_config.Subnet(ipaddress.ip_network(_AP_2GHZ_SUBNET_STR))
_AP_5GHZ_SUBNET = dhcp_config.Subnet(ipaddress.ip_network(_AP_5GHZ_SUBNET_STR))
-LAN_INTERFACE = 'eth1'
# The last digit of the ip for the bridge interface
BRIDGE_IP_LAST = '100'
@@ -119,7 +118,40 @@
# A map from network interface name to _ApInstance objects representing
# the hostapd instance running against the interface.
self._aps = dict()
- self.bridge = bridge_interface.BridgeInterface(self.ssh)
+ self.bridge = bridge_interface.BridgeInterface(self)
+ self.interfaces = ap_get_interface.ApInterfaces(self)
+
+ # Get needed interface names and initialize the unneccessary ones.
+ self.wan = self.interfaces.get_wan_interface()
+ self.wlan = self.interfaces.get_wlan_interface()
+ self.wlan_2g = self.wlan[0]
+ self.wlan_5g = self.wlan[1]
+ self.lan = self.interfaces.get_lan_interface()
+ self.__initial_ap()
+
+ def __initial_ap(self):
+ """Initial AP interfaces.
+
+ Bring down hostapd if instance is running, bring down all bridge
+ interfaces.
+ """
+ # Stop hostapd instance if running
+ try:
+ self.ssh.run('stop hostapd')
+ except job.Error:
+ logging.debug('No hostapd running')
+ # Bring down all wireless interfaces
+ for iface in self.wlan:
+ WLAN_DOWN = 'ifconfig {} down'.format(iface)
+ self.ssh.run(WLAN_DOWN)
+ # Bring down all bridge interfaces
+ bridge_interfaces = self.interfaces.get_bridge_interface()
+ if bridge_interfaces:
+ for iface in bridge_interfaces:
+ BRIDGE_DOWN = 'ifconfig {} down'.format(iface)
+ BRIDGE_DEL = 'brctl delbr {}'.format(iface)
+ self.ssh.run(BRIDGE_DOWN)
+ self.ssh.run(BRIDGE_DEL)
def start_ap(self, hostapd_config, additional_parameters=None):
"""Starts as an ap using a set of configurations.
@@ -145,15 +177,12 @@
Raises:
Error: When the ap can't be brought up.
"""
- # Right now, we hardcode that a frequency maps to a particular
- # network interface. This is true of the hardware we're running
- # against right now, but in general, we'll want to do some
- # dynamic discovery of interface capabilities. See b/32582843
+
if hostapd_config.frequency < 5000:
- interface = _AP_2GHZ_INTERFACE
+ interface = self.wlan_2g
subnet = _AP_2GHZ_SUBNET
else:
- interface = _AP_5GHZ_INTERFACE
+ interface = self.wlan_5g
subnet = _AP_5GHZ_SUBNET
# In order to handle dhcp servers on any interface, the initiation of
@@ -202,14 +231,14 @@
bss].bssid = interface_mac_orig.stdout[:-1] + str(
counter)
self._route_cmd.clear_routes(net_interface=str(bss))
- if interface is _AP_2GHZ_INTERFACE:
+ if interface is self.wlan_2g:
starting_ip_range = _AP_2GHZ_SUBNET_STR
else:
starting_ip_range = _AP_5GHZ_SUBNET_STR
a, b, c, d = starting_ip_range.split('.')
dhcp_bss[bss] = dhcp_config.Subnet(
- ipaddress.ip_network('%s.%s.%s.%s' % (a, b, str(
- int(c) + counter), d)))
+ ipaddress.ip_network('%s.%s.%s.%s' %
+ (a, b, str(int(c) + counter), d)))
counter = counter + 1
apd.start(hostapd_config, additional_parameters=additional_parameters)
@@ -238,6 +267,15 @@
self._dhcp.start(config=dhcp_config.DhcpConfig(configured_subnets))
+ # The following three commands are needed to enable bridging between
+ # the WAN and LAN/WLAN ports. This means anyone connecting to the
+ # WLAN/LAN ports will be able to access the internet if the WAN port
+ # is connected to the internet.
+ self.ssh.run('iptables -t nat -F')
+ self.ssh.run(
+ 'iptables -t nat -A POSTROUTING -o %s -j MASQUERADE' % self.wan)
+ self.ssh.run('echo 1 > /proc/sys/net/ipv4/ip_forward')
+
return interface
def get_bssid_from_ssid(self, ssid):
@@ -248,7 +286,7 @@
Returns: The BSSID if on the AP or None if SSID could not be found.
"""
- interfaces = [_AP_2GHZ_INTERFACE, _AP_5GHZ_INTERFACE, ssid]
+ interfaces = [self.wlan_2g, self.wlan_5g, ssid]
# Get the interface name associated with the given ssid.
for interface in interfaces:
cmd = "iw dev %s info|grep ssid|awk -F' ' '{print $2}'" % (
@@ -311,7 +349,7 @@
self.stop_all_aps()
self.ssh.close()
- def generate_bridge_configs(self, channel, iface_lan=LAN_INTERFACE):
+ def generate_bridge_configs(self, channel):
"""Generate a list of configs for a bridge between LAN and WLAN.
Args:
@@ -322,13 +360,13 @@
"""
if channel < 15:
- iface_wlan = _AP_2GHZ_INTERFACE
+ iface_wlan = self.wlan_2g
subnet_str = _AP_2GHZ_SUBNET_STR
else:
- iface_wlan = _AP_5GHZ_INTERFACE
+ iface_wlan = self.wlan_5g
subnet_str = _AP_5GHZ_SUBNET_STR
- iface_lan = iface_lan
+ iface_lan = self.lan
a, b, c, d = subnet_str.strip('/24').split('.')
bridge_ip = "%s.%s.%s.%s" % (a, b, c, BRIDGE_IP_LAST)
diff --git a/acts/framework/acts/controllers/ap_lib/ap_get_interface.py b/acts/framework/acts/controllers/ap_lib/ap_get_interface.py
new file mode 100644
index 0000000..65c8938
--- /dev/null
+++ b/acts/framework/acts/controllers/ap_lib/ap_get_interface.py
@@ -0,0 +1,184 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - Google, Inc.
+#
+# 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 logging
+from acts.libs.proc import job
+
+GET_ALL_INTERFACE = 'ls /sys/class/net'
+GET_VIRTUAL_INTERFACE = 'ls /sys/devices/virtual/net'
+BRCTL_SHOW = 'brctl show'
+
+
+class ApInterfacesError(Exception):
+ """Error related to AP interfaces."""
+
+
+class ApInterfaces(object):
+ """Class to get network interface information for the device.
+
+ """
+
+ def __init__(self, ap):
+ """Initialize the ApInterface class.
+
+ Args:
+ ap: the ap object within ACTS
+ """
+ self.ssh = ap.ssh
+
+ def get_all_interface(self):
+ """Get all network interfaces on the device.
+
+ Returns:
+ interfaces_all: list of all the network interfaces on device
+ """
+ output = self.ssh.run(GET_ALL_INTERFACE)
+ interfaces_all = output.stdout.split('\n')
+
+ return interfaces_all
+
+ def get_virtual_interface(self):
+ """Get all virtual interfaces on the device.
+
+ Returns:
+ interfaces_virtual: list of all the virtual interfaces on device
+ """
+ output = self.ssh.run(GET_VIRTUAL_INTERFACE)
+ interfaces_virtual = output.stdout.split('\n')
+
+ return interfaces_virtual
+
+ def get_physical_interface(self):
+ """Get all the physical interfaces of the device.
+
+ Get all physical interfaces such as eth ports and wlan ports
+ Returns:
+ interfaces_phy: list of all the physical interfaces
+ """
+ interfaces_all = self.get_all_interface()
+ interfaces_virtual = self.get_virtual_interface()
+ interfaces_phy = list(set(interfaces_all) - set(interfaces_virtual))
+
+ return interfaces_phy
+
+ def get_bridge_interface(self):
+ """Get all the bridge interfaces of the device.
+
+ Returns:
+ interfaces_bridge: the list of bridge interfaces, return None if
+ bridge utility is not available on the device
+ """
+ interfaces_bridge = []
+ try:
+ output = self.ssh.run(BRCTL_SHOW)
+ lines = output.stdout.split('\n')
+ for line in lines:
+ interfaces_bridge.append(line.split('\t')[0])
+ interfaces_bridge.pop(0)
+ interfaces_bridge = [x for x in interfaces_bridge if x is not '']
+ return interfaces_bridge
+ except job.Error:
+ logging.info('No brctl utility is available')
+ return None
+
+ def get_wlan_interface(self):
+ """Get all WLAN interfaces and specify 2.4 GHz and 5 GHz interfaces.
+
+ Returns:
+ interfaces_wlan: all wlan interfaces
+ Raises:
+ ApInterfacesError: Missing at least one WLAN interface
+ """
+ wlan_2g = None
+ wlan_5g = None
+ interfaces_phy = self.get_physical_interface()
+ for iface in interfaces_phy:
+ IW_LIST_FREQ = 'iwlist %s freq' % iface
+ output = self.ssh.run(IW_LIST_FREQ)
+ if 'Channel 06' in output.stdout and 'Channel 36' not in output.stdout:
+ wlan_2g = iface
+ elif 'Channel 36' in output.stdout and 'Channel 06' not in output.stdout:
+ wlan_5g = iface
+
+ interfaces_wlan = [wlan_2g, wlan_5g]
+
+ if None not in interfaces_wlan:
+ return interfaces_wlan
+
+ raise ApInterfacesError('Missing at least one WLAN interface')
+
+ def get_wan_interface(self):
+ """Get the WAN interface which has internet connectivity.
+
+ Returns:
+ wan: the only one WAN interface
+ Raises:
+ ApInterfacesError: no running WAN can be found
+ """
+ wan = None
+ interfaces_phy = self.get_physical_interface()
+ interfaces_wlan = self.get_wlan_interface()
+ interfaces_eth = list(set(interfaces_phy) - set(interfaces_wlan))
+ for iface in interfaces_eth:
+ network_status = self.check_ping(iface)
+ if network_status == 1:
+ wan = iface
+ break
+ if wan:
+ return wan
+
+ raise ApInterfacesError('No WAN interface available')
+
+ def get_lan_interface(self):
+ """Get the LAN interface connecting to local devices.
+
+ Returns:
+ lan: the only one running LAN interface of the devices
+ Raises:
+ ApInterfacesError: no running LAN can be found
+ """
+ lan = None
+ interfaces_phy = self.get_physical_interface()
+ interfaces_wlan = self.get_wlan_interface()
+ interfaces_eth = list(set(interfaces_phy) - set(interfaces_wlan))
+ interface_wan = self.get_wan_interface()
+ interfaces_eth.remove(interface_wan)
+ for iface in interfaces_eth:
+ LAN_CHECK = 'ifconfig %s' % iface
+ output = self.ssh.run(LAN_CHECK)
+ if 'RUNNING' in output.stdout:
+ lan = iface
+ break
+ if lan:
+ return lan
+
+ raise ApInterfacesError(
+ 'No running LAN interface available, check connection')
+
+ def check_ping(self, iface):
+ """Check the ping status on specific interface to determine the WAN.
+
+ Args:
+ iface: the specific interface to check
+ Returns:
+ network_status: the connectivity status of the interface
+ """
+ PING = 'ping -c 1 -I %s 8.8.8.8' % iface
+ try:
+ self.ssh.run(PING)
+ return 1
+ except job.Error:
+ return 0
diff --git a/acts/framework/acts/controllers/ap_lib/bridge_interface.py b/acts/framework/acts/controllers/ap_lib/bridge_interface.py
index af3d072..be4d291 100644
--- a/acts/framework/acts/controllers/ap_lib/bridge_interface.py
+++ b/acts/framework/acts/controllers/ap_lib/bridge_interface.py
@@ -18,9 +18,8 @@
import time
from acts.libs.proc import job
-# TODO(@qijiang): will change to brctl when it's built in image
-_BRCTL = '/home/root/bridge-utils/sbin/brctl'
-BRIDGE_NAME = 'br0'
+_BRCTL = 'brctl'
+BRIDGE_NAME = 'br-lan'
CREATE_BRIDGE = '%s addbr %s' % (_BRCTL, BRIDGE_NAME)
DELETE_BRIDGE = '%s delbr %s' % (_BRCTL, BRIDGE_NAME)
BRING_DOWN_BRIDGE = 'ifconfig %s down' % BRIDGE_NAME
@@ -48,16 +47,14 @@
"""Class object for bridge interface betwen WLAN and LAN
"""
-
- def __init__(self, ssh_session):
+ def __init__(self, ap):
"""Initialize the BridgeInterface class.
Bridge interface will be added between ethernet LAN port and WLAN port.
Args:
- ssh_session: ssh session to the AP
+ ap: AP object within ACTS
"""
- self.ssh = ssh_session
- self.log = logging.getLogger()
+ self.ssh = ap.ssh
def startup(self, brconfigs):
"""Start up the bridge interface.
@@ -66,12 +63,12 @@
brconfigs: the bridge interface config, type BridgeInterfaceConfigs
"""
- self.log.info('Create bridge interface between LAN and WLAN')
+ logging.info('Create bridge interface between LAN and WLAN')
# Create the bridge
try:
self.ssh.run(CREATE_BRIDGE)
except job.Error:
- self.log.warning(
+ logging.warning(
'Bridge interface {} already exists, no action needed'.format(
BRIDGE_NAME))
@@ -80,8 +77,8 @@
try:
self.ssh.run(ENABLE_4ADDR)
except job.Error:
- self.log.warning(
- '4addr is already enabled on {}'.format(brconfigs.iface_wlan))
+ logging.warning('4addr is already enabled on {}'.format(
+ brconfigs.iface_wlan))
# Add both LAN and WLAN interfaces to the bridge interface
for interface in [brconfigs.iface_lan, brconfigs.iface_wlan]:
@@ -89,7 +86,7 @@
try:
self.ssh.run(ADD_INTERFACE)
except job.Error:
- self.log.warning('{} has alrady been added to {}'.format(
+ logging.warning('{} has alrady been added to {}'.format(
interface, BRIDGE_NAME))
time.sleep(5)
@@ -99,7 +96,7 @@
time.sleep(2)
# Bridge interface is up
- self.log.info('Bridge interface is up and running')
+ logging.info('Bridge interface is up and running')
def teardown(self, brconfigs):
"""Tear down the bridge interface.
@@ -107,7 +104,7 @@
Args:
brconfigs: the bridge interface config, type BridgeInterfaceConfigs
"""
- self.log.info('Bringing down the bridge interface')
+ logging.info('Bringing down the bridge interface')
# Delete the bridge interface
self.ssh.run(BRING_DOWN_BRIDGE)
time.sleep(1)
@@ -120,4 +117,4 @@
DISABLE_4ADDR = 'iw dev %s set 4addr off' % (brconfigs.iface_wlan)
self.ssh.run(DISABLE_4ADDR)
time.sleep(1)
- self.log.info('Bridge interface is down')
+ logging.info('Bridge interface is down')
diff --git a/acts/framework/acts/controllers/ap_lib/dhcp_server.py b/acts/framework/acts/controllers/ap_lib/dhcp_server.py
index 59f1f2f..6d81360 100644
--- a/acts/framework/acts/controllers/ap_lib/dhcp_server.py
+++ b/acts/framework/acts/controllers/ap_lib/dhcp_server.py
@@ -12,18 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import collections
-import itertools
-import os
import time
-
-from acts.controllers.ap_lib import dhcp_config
from acts.controllers.utils_lib.commands import shell
-# The router wan interface will be hard set since this the default for the
-# whirlwind. In the future it maybe desireable to see which interface has a
-# public address and assign it dynamically.
-_ROUTER_WAN_INTERFACE = 'eth2'
_ROUTER_DNS = '8.8.8.8, 4.4.4.4'
@@ -81,15 +72,6 @@
if self.is_alive():
self.stop()
- # The following three commands are needed to enable bridging between
- # the WAN and LAN/WLAN ports. This means anyone connecting to the
- # WLAN/LAN ports will be able to access the internet if the WAN port
- # is connected to the internet.
- self._runner.run('iptables -t nat -F')
- self._runner.run('iptables -t nat -A POSTROUTING -o %s -j MASQUERADE' %
- _ROUTER_WAN_INTERFACE)
- self._runner.run('echo 1 > /proc/sys/net/ipv4/ip_forward')
-
self._write_configs(config)
self._shell.delete_file(self._log_file)
self._shell.touch_file(self._lease_file)
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd_ap_preset.py b/acts/framework/acts/controllers/ap_lib/hostapd_ap_preset.py
index a18f0c7..845f3d3 100644
--- a/acts/framework/acts/controllers/ap_lib/hostapd_ap_preset.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd_ap_preset.py
@@ -18,10 +18,14 @@
def create_ap_preset(profile_name,
channel=None,
+ dtim=2,
frequency=None,
security=None,
ssid=None,
- bss_settings=[]):
+ vht_bandwidth=80,
+ bss_settings=[],
+ iface_wlan_2g=hostapd_constants.WLAN0_STRING,
+ iface_wlan_5g=hostapd_constants.WLAN1_STRING):
"""AP preset config generator. This a wrapper for hostapd_config but
but supplies the default settings for the preset that is selected.
@@ -33,10 +37,14 @@
profile_name: The name of the device want the preset for.
Options: whirlwind
channel: int, channel number.
+ dtim: int, DTIM value of the AP, default is 2.
frequency: int, frequency of channel.
security: Security, the secuirty settings to use.
ssid: string, The name of the ssid to brodcast.
+ vht_bandwidth: VHT bandwidth for 11ac operation.
bss_settings: The settings for all bss.
+ iface_wlan_2g: the wlan 2g interface name of the AP.
+ iface_wlan_5g: the wlan 5g interface name of the AP.
Returns: A hostapd_config object that can be used by the hostapd object.
"""
@@ -60,10 +68,9 @@
if (profile_name == 'whirlwind'):
force_wmm = True
beacon_interval = 100
- dtim_period = 2
short_preamble = True
if frequency < 5000:
- interface = hostapd_constants.WLAN0_STRING
+ interface = iface_wlan_2g
mode = hostapd_constants.MODE_11N_MIXED
n_capabilities = [
hostapd_constants.N_CAPABILITY_LDPC,
@@ -86,19 +93,30 @@
n_capabilities=n_capabilities,
bss_settings=bss_settings)
else:
- interface = hostapd_constants.WLAN1_STRING
+ interface = iface_wlan_5g
mode = hostapd_constants.MODE_11AC_MIXED
if hostapd_config.ht40_plus_allowed(channel):
extended_channel = hostapd_constants.N_CAPABILITY_HT40_PLUS
elif hostapd_config.ht40_minus_allowed(channel):
extended_channel = hostapd_constants.N_CAPABILITY_HT40_MINUS
- n_capabilities = [
- hostapd_constants.N_CAPABILITY_LDPC, extended_channel,
- hostapd_constants.N_CAPABILITY_SGI20,
- hostapd_constants.N_CAPABILITY_SGI40,
- hostapd_constants.N_CAPABILITY_TX_STBC,
- hostapd_constants.N_CAPABILITY_RX_STBC1
- ]
+ # Define the n capability vector for 20 MHz and higher bandwidth
+ if vht_bandwidth >= 40:
+ n_capabilities = [
+ hostapd_constants.N_CAPABILITY_LDPC, extended_channel,
+ hostapd_constants.N_CAPABILITY_SGI20,
+ hostapd_constants.N_CAPABILITY_SGI40,
+ hostapd_constants.N_CAPABILITY_TX_STBC,
+ hostapd_constants.N_CAPABILITY_RX_STBC1
+ ]
+ else:
+ n_capabilities = [
+ hostapd_constants.N_CAPABILITY_LDPC,
+ hostapd_constants.N_CAPABILITY_SGI20,
+ hostapd_constants.N_CAPABILITY_SGI40,
+ hostapd_constants.N_CAPABILITY_TX_STBC,
+ hostapd_constants.N_CAPABILITY_RX_STBC1,
+ hostapd_constants.N_CAPABILITY_HT20
+ ]
ac_capabilities = [
hostapd_constants.AC_CAPABILITY_MAX_MPDU_11454,
hostapd_constants.AC_CAPABILITY_RXLDPC,
@@ -115,6 +133,7 @@
interface=interface,
mode=mode,
force_wmm=force_wmm,
+ vht_channel_width=vht_bandwidth,
beacon_interval=beacon_interval,
dtim_period=dtim_period,
short_preamble=short_preamble,
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd_config.py b/acts/framework/acts/controllers/ap_lib/hostapd_config.py
index 4c70bd7..bfc0ca3 100644
--- a/acts/framework/acts/controllers/ap_lib/hostapd_config.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd_config.py
@@ -428,7 +428,8 @@
self._pmf_support = pmf_support
self._obss_interval = obss_interval
if self.is_11ac:
- if str(vht_channel_width) == '40':
+ if str(vht_channel_width) == '40' or str(
+ vht_channel_width) == '20':
self._vht_oper_chwidth = hostapd_constants.VHT_CHANNEL_WIDTH_40
elif str(vht_channel_width) == '80':
self._vht_oper_chwidth = hostapd_constants.VHT_CHANNEL_WIDTH_80
@@ -442,9 +443,10 @@
logging.warning(
'No channel bandwidth specified. Using 80MHz for 11ac.')
self._vht_oper_chwidth = 1
- if not vht_center_channel:
- self._vht_oper_centr_freq_seg0_idx = self._get_11ac_center_channel_from_channel(
- self.channel)
+ if not vht_channel_width == 20:
+ if not vht_center_channel:
+ self._vht_oper_centr_freq_seg0_idx = self._get_11ac_center_channel_from_channel(
+ self.channel)
else:
self._vht_oper_centr_freq_seg0_idx = vht_center_channel
self._ac_capabilities = set(ac_capabilities)
@@ -461,16 +463,16 @@
self._bss_lookup[bss.name] = bss
def __repr__(self):
- return (
- '%s(mode=%r, channel=%r, frequency=%r, '
- 'n_capabilities=%r, beacon_interval=%r, '
- 'dtim_period=%r, frag_threshold=%r, ssid=%r, bssid=%r, '
- 'wmm_enabled=%r, security_config=%r, '
- 'spectrum_mgmt_required=%r)' %
- (self.__class__.__name__, self._mode, self.channel, self.frequency,
- self._n_capabilities, self._beacon_interval, self._dtim_period,
- self._frag_threshold, self._ssid, self._bssid, self._wmm_enabled,
- self._security, self._spectrum_mgmt_required))
+ return ('%s(mode=%r, channel=%r, frequency=%r, '
+ 'n_capabilities=%r, beacon_interval=%r, '
+ 'dtim_period=%r, frag_threshold=%r, ssid=%r, bssid=%r, '
+ 'wmm_enabled=%r, security_config=%r, '
+ 'spectrum_mgmt_required=%r)' %
+ (self.__class__.__name__, self._mode, self.channel,
+ self.frequency, self._n_capabilities, self._beacon_interval,
+ self._dtim_period, self._frag_threshold, self._ssid,
+ self._bssid, self._wmm_enabled, self._security,
+ self._spectrum_mgmt_required))
def supports_channel(self, value):
"""Check whether channel is supported by the current hardware mode.
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd_constants.py b/acts/framework/acts/controllers/ap_lib/hostapd_constants.py
index 4e43eab..11cfaa5 100755
--- a/acts/framework/acts/controllers/ap_lib/hostapd_constants.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd_constants.py
@@ -110,6 +110,7 @@
MODE_11AC_PURE = 'ac-only'
N_CAPABILITY_LDPC = object()
+N_CAPABILITY_HT20 = object()
N_CAPABILITY_HT40_PLUS = object()
N_CAPABILITY_HT40_MINUS = object()
N_CAPABILITY_GREENFIELD = object()
@@ -122,6 +123,7 @@
N_CAPABILITY_DSSS_CCK_40 = object()
N_CAPABILITIES_MAPPING = {
N_CAPABILITY_LDPC: '[LDPC]',
+ N_CAPABILITY_HT20: '[HT20]',
N_CAPABILITY_HT40_PLUS: '[HT40+]',
N_CAPABILITY_HT40_MINUS: '[HT40-]',
N_CAPABILITY_GREENFIELD: '[GF]',
@@ -212,10 +214,12 @@
# tolerate HT40+ on channel 7 (not allowed in the US). We take the loose
# definition so that we don't prohibit testing in either domain.
HT40_ALLOW_MAP = {
- N_CAPABILITY_HT40_MINUS_CHANNELS: tuple(
+ N_CAPABILITY_HT40_MINUS_CHANNELS:
+ tuple(
itertools.chain(
range(6, 14), range(40, 65, 8), range(104, 137, 8), [153, 161])),
- N_CAPABILITY_HT40_PLUS_CHANNELS: tuple(
+ N_CAPABILITY_HT40_PLUS_CHANNELS:
+ tuple(
itertools.chain(
range(1, 8), range(36, 61, 8), range(100, 133, 8), [149, 157]))
}
diff --git a/acts/framework/acts/test_utils/wifi/wifi_power_test_utils.py b/acts/framework/acts/test_utils/wifi/wifi_power_test_utils.py
index 1927d36..7fdbbf0 100644
--- a/acts/framework/acts/test_utils/wifi/wifi_power_test_utils.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_power_test_utils.py
@@ -212,14 +212,15 @@
color = ['navy'] * len(current_data)
#Preparing the data and source link for bokehn java callback
- source = ColumnDataSource(data=dict(
- x0=time_relative, y0=current_data, color=color))
- s2 = ColumnDataSource(data=dict(
- z0=[mon_info['duration']],
- y0=[round(avg_current, 2)],
- x0=[round(avg_current * voltage, 2)],
- z1=[round(avg_current * voltage * mon_info['duration'], 2)],
- z2=[round(avg_current * mon_info['duration'], 2)]))
+ source = ColumnDataSource(
+ data=dict(x0=time_relative, y0=current_data, color=color))
+ s2 = ColumnDataSource(
+ data=dict(
+ z0=[mon_info['duration']],
+ y0=[round(avg_current, 2)],
+ x0=[round(avg_current * voltage, 2)],
+ z1=[round(avg_current * voltage * mon_info['duration'], 2)],
+ z2=[round(avg_current * mon_info['duration'], 2)]))
#Setting up data table for the output
columns = [
TableColumn(field='z0', title='Total Duration (s)'),
@@ -349,15 +350,15 @@
ad.log.info('DTIM updated and device back from reboot')
-def ap_setup(ap, network):
+def ap_setup(ap, network, bandwidth=80):
"""Set up the whirlwind AP with provided network info.
Args:
ap: access_point object of the AP
network: dict with information of the network, including ssid, password
bssid, channel etc.
+ bandwidth: the operation bandwidth for the AP, default 80MHz
"""
-
log = logging.getLogger()
bss_settings = []
ssid = network[wutils.WifiEnums.SSID_KEY]
@@ -373,7 +374,10 @@
ssid=ssid,
security=security,
bss_settings=bss_settings,
- profile_name='whirlwind')
+ vht_bandwidth=bandwidth,
+ profile_name='whirlwind',
+ iface_wlan_2g=ap.wlan_2g,
+ iface_wlan_5g=ap.wlan_5g)
ap.start_ap(config)
log.info("AP started on channel {} with SSID {}".format(channel, ssid))