blob: bf5b5f641f0b9d49f7e0d4238e4fa9d9cc053758 [file] [log] [blame]
Bindu Mahadeve57533d2018-05-22 16:35:03 -07001#!/usr/bin/env python3
Ang Li73697b32015-12-03 00:41:53 +00002#
tturney1bdf77d2015-12-28 17:46:13 -08003# Copyright 2016 - Google, Inc.
Ang Li73697b32015-12-03 00:41:53 +00004#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Christopher Wileyede81f02016-11-01 09:15:30 -070017import collections
Benny Peake85f112a2016-10-07 19:41:49 -070018import ipaddress
Bindu Mahadeve57533d2018-05-22 16:35:03 -070019import logging
Qi Jiangef7de182017-12-05 14:56:08 -080020import time
Ang Li73697b32015-12-03 00:41:53 +000021
Qi Jiangef7de182017-12-05 14:56:08 -080022from acts.controllers.ap_lib import ap_get_interface
Qi Jiangc3e87852017-10-04 22:45:52 -070023from acts.controllers.ap_lib import bridge_interface
Benny Peake85f112a2016-10-07 19:41:49 -070024from acts.controllers.ap_lib import dhcp_config
25from acts.controllers.ap_lib import dhcp_server
26from acts.controllers.ap_lib import hostapd
Bindu Mahadeve57533d2018-05-22 16:35:03 -070027from acts.controllers.ap_lib import hostapd_config
Benny Peake85f112a2016-10-07 19:41:49 -070028from acts.controllers.utils_lib.commands import ip
29from acts.controllers.utils_lib.commands import route
Bindu Mahadeve57533d2018-05-22 16:35:03 -070030from acts.controllers.utils_lib.commands import shell
Benny Peake85f112a2016-10-07 19:41:49 -070031from acts.controllers.utils_lib.ssh import connection
32from acts.controllers.utils_lib.ssh import settings
Qi Jiangef7de182017-12-05 14:56:08 -080033from acts.libs.proc import job
Benny Peake85f112a2016-10-07 19:41:49 -070034
35ACTS_CONTROLLER_CONFIG_NAME = 'AccessPoint'
Benny Peake0f5049b2016-10-28 15:57:01 -070036ACTS_CONTROLLER_REFERENCE_NAME = 'access_points'
Qi Jiangef7de182017-12-05 14:56:08 -080037_BRCTL = 'brctl'
Benny Peake85f112a2016-10-07 19:41:49 -070038
Ang Li51df0452016-06-07 10:58:16 -070039
Ang Lia11f2cf2016-05-05 11:54:40 -070040def create(configs):
Benny Peake85f112a2016-10-07 19:41:49 -070041 """Creates ap controllers from a json config.
42
43 Creates an ap controller from either a list, or a single
44 element. The element can either be just the hostname or a dictionary
45 containing the hostname and username of the ap to connect to over ssh.
46
47 Args:
48 The json configs that represent this controller.
49
50 Returns:
51 A new AccessPoint.
52 """
Qi Jiang4d8b7cb2018-02-06 23:13:44 -080053 return [AccessPoint(c) for c in configs]
Ang Li73697b32015-12-03 00:41:53 +000054
Ang Li51df0452016-06-07 10:58:16 -070055
Benny Peake85f112a2016-10-07 19:41:49 -070056def destroy(aps):
57 """Destroys a list of access points.
Ang Li73697b32015-12-03 00:41:53 +000058
Benny Peake85f112a2016-10-07 19:41:49 -070059 Args:
60 aps: The list of access points to destroy.
Ang Li73697b32015-12-03 00:41:53 +000061 """
Benny Peake85f112a2016-10-07 19:41:49 -070062 for ap in aps:
63 ap.close()
Ang Li73697b32015-12-03 00:41:53 +000064
Ang Li73697b32015-12-03 00:41:53 +000065
Benny Peake85f112a2016-10-07 19:41:49 -070066def get_info(aps):
67 """Get information on a list of access points.
Ang Li73697b32015-12-03 00:41:53 +000068
Benny Peake85f112a2016-10-07 19:41:49 -070069 Args:
70 aps: A list of AccessPoints.
71
72 Returns:
73 A list of all aps hostname.
74 """
Christopher Wiley7dae1d92016-10-31 14:47:58 -070075 return [ap.ssh_settings.hostname for ap in aps]
Benny Peake85f112a2016-10-07 19:41:49 -070076
77
78class Error(Exception):
79 """Error raised when there is a problem with the access point."""
80
81
Joe Brennan88279af2017-02-15 18:11:53 -080082_ApInstance = collections.namedtuple('_ApInstance', ['hostapd', 'subnet'])
Christopher Wileyede81f02016-11-01 09:15:30 -070083
Joe Brennan88279af2017-02-15 18:11:53 -080084# These ranges were split this way since each physical radio can have up
85# to 8 SSIDs so for the 2GHz radio the DHCP range will be
86# 192.168.1 - 8 and the 5Ghz radio will be 192.168.9 - 16
Qi Jiang4d8b7cb2018-02-06 23:13:44 -080087_AP_2GHZ_SUBNET_STR_DEFAULT = '192.168.1.0/24'
88_AP_5GHZ_SUBNET_STR_DEFAULT = '192.168.9.0/24'
89
Qi Jiangc3e87852017-10-04 22:45:52 -070090# The last digit of the ip for the bridge interface
91BRIDGE_IP_LAST = '100'
Christopher Wileyede81f02016-11-01 09:15:30 -070092
93
Benny Peake85f112a2016-10-07 19:41:49 -070094class AccessPoint(object):
95 """An access point controller.
96
97 Attributes:
Benny Peake85f112a2016-10-07 19:41:49 -070098 ssh: The ssh connection to this ap.
markdrb629b322017-05-22 13:44:06 -070099 ssh_settings: The ssh settings being used by the ssh connection.
Benny Peake85f112a2016-10-07 19:41:49 -0700100 dhcp_settings: The dhcp server settings being used.
101 """
102
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800103 def __init__(self, configs):
Benny Peake85f112a2016-10-07 19:41:49 -0700104 """
105 Args:
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800106 configs: configs for the access point from config file.
Benny Peake85f112a2016-10-07 19:41:49 -0700107 """
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800108 self.ssh_settings = settings.from_config(configs['ssh_config'])
109 if 'ap_subnet' in configs:
110 self._AP_2G_SUBNET_STR = configs['ap_subnet']['2g']
111 self._AP_5G_SUBNET_STR = configs['ap_subnet']['5g']
112 else:
113 self._AP_2G_SUBNET_STR = _AP_2GHZ_SUBNET_STR_DEFAULT
114 self._AP_5G_SUBNET_STR = _AP_5GHZ_SUBNET_STR_DEFAULT
115
116 self._AP_2G_SUBNET = dhcp_config.Subnet(
117 ipaddress.ip_network(self._AP_2G_SUBNET_STR))
118 self._AP_5G_SUBNET = dhcp_config.Subnet(
119 ipaddress.ip_network(self._AP_5G_SUBNET_STR))
120
Benny Peake85f112a2016-10-07 19:41:49 -0700121 self.ssh = connection.SshConnection(self.ssh_settings)
122
Christopher Wileyede81f02016-11-01 09:15:30 -0700123 # Singleton utilities for running various commands.
Benny Peake85f112a2016-10-07 19:41:49 -0700124 self._ip_cmd = ip.LinuxIpCommand(self.ssh)
125 self._route_cmd = route.LinuxRouteCommand(self.ssh)
126
Christopher Wileyede81f02016-11-01 09:15:30 -0700127 # A map from network interface name to _ApInstance objects representing
128 # the hostapd instance running against the interface.
129 self._aps = dict()
Qi Jiangef7de182017-12-05 14:56:08 -0800130 self.bridge = bridge_interface.BridgeInterface(self)
131 self.interfaces = ap_get_interface.ApInterfaces(self)
132
Bindu Mahadeve57533d2018-05-22 16:35:03 -0700133 # Get needed interface names and initialize the unneccessary ones.
Qi Jiangef7de182017-12-05 14:56:08 -0800134 self.wan = self.interfaces.get_wan_interface()
135 self.wlan = self.interfaces.get_wlan_interface()
136 self.wlan_2g = self.wlan[0]
137 self.wlan_5g = self.wlan[1]
138 self.lan = self.interfaces.get_lan_interface()
139 self.__initial_ap()
140
141 def __initial_ap(self):
142 """Initial AP interfaces.
143
144 Bring down hostapd if instance is running, bring down all bridge
Bindu Mahadev18c5f602018-03-26 23:10:27 +0000145 interfaces.
Qi Jiangef7de182017-12-05 14:56:08 -0800146 """
Qi Jiangef7de182017-12-05 14:56:08 -0800147 try:
Qi Jiang0a4c5e82018-04-13 12:13:14 -0700148 # This is necessary for Gale/Whirlwind flashed with dev channel image
149 # Unused interfaces such as existing hostapd daemon, guest, mesh
150 # interfaces need to be brought down as part of the AP initialization
151 # process, otherwise test would fail.
Mark De Ruyter4a4cd7c2018-03-30 20:17:43 +0000152 try:
153 self.ssh.run('stop hostapd')
154 except job.Error:
155 self.log.debug('No hostapd running')
156 # Bring down all wireless interfaces
157 for iface in self.wlan:
158 WLAN_DOWN = 'ifconfig {} down'.format(iface)
159 self.ssh.run(WLAN_DOWN)
160 # Bring down all bridge interfaces
161 bridge_interfaces = self.interfaces.get_bridge_interface()
162 if bridge_interfaces:
163 for iface in bridge_interfaces:
164 BRIDGE_DOWN = 'ifconfig {} down'.format(iface)
165 BRIDGE_DEL = 'brctl delbr {}'.format(iface)
166 self.ssh.run(BRIDGE_DOWN)
167 self.ssh.run(BRIDGE_DEL)
168 except Exception:
169 # TODO(b/76101464): APs may not clean up properly from previous
170 # runs. Rebooting the AP can put them back into the correct state.
171 self.log.exception('Unable to bring down hostapd. Rebooting.')
172 # Reboot the AP.
173 try:
174 self.ssh.run('reboot')
175 # This sleep ensures the device had time to go down.
176 time.sleep(10)
177 self.ssh.run('echo connected', timeout=300)
178 except Exception as e:
179 self.log.exception("Error in rebooting AP: %s", e)
180 raise
Christopher Wileyede81f02016-11-01 09:15:30 -0700181
Joe Brennan88279af2017-02-15 18:11:53 -0800182 def start_ap(self, hostapd_config, additional_parameters=None):
Benny Peake85f112a2016-10-07 19:41:49 -0700183 """Starts as an ap using a set of configurations.
184
185 This will start an ap on this host. To start an ap the controller
186 selects a network interface to use based on the configs given. It then
187 will start up hostapd on that interface. Next a subnet is created for
188 the network interface and dhcp server is refreshed to give out ips
189 for that subnet for any device that connects through that interface.
Ang Li73697b32015-12-03 00:41:53 +0000190
191 Args:
Benny Peake85f112a2016-10-07 19:41:49 -0700192 hostapd_config: hostapd_config.HostapdConfig, The configurations
193 to use when starting up the ap.
markdrb629b322017-05-22 13:44:06 -0700194 additional_parameters: A dictionary of parameters that can sent
Joe Brennan88279af2017-02-15 18:11:53 -0800195 directly into the hostapd config file. This
196 can be used for debugging and or adding one
197 off parameters into the config.
Ang Li73697b32015-12-03 00:41:53 +0000198
199 Returns:
Benny Peake85f112a2016-10-07 19:41:49 -0700200 An identifier for the ap being run. This identifier can be used
201 later by this controller to control the ap.
Ang Li73697b32015-12-03 00:41:53 +0000202
203 Raises:
Benny Peake85f112a2016-10-07 19:41:49 -0700204 Error: When the ap can't be brought up.
Ang Li73697b32015-12-03 00:41:53 +0000205 """
Qi Jiangef7de182017-12-05 14:56:08 -0800206
Benny Peake85f112a2016-10-07 19:41:49 -0700207 if hostapd_config.frequency < 5000:
Qi Jiangef7de182017-12-05 14:56:08 -0800208 interface = self.wlan_2g
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800209 subnet = self._AP_2G_SUBNET
Benny Peake85f112a2016-10-07 19:41:49 -0700210 else:
Qi Jiangef7de182017-12-05 14:56:08 -0800211 interface = self.wlan_5g
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800212 subnet = self._AP_5G_SUBNET
Christopher Wileyede81f02016-11-01 09:15:30 -0700213
Joe Brennan88279af2017-02-15 18:11:53 -0800214 # In order to handle dhcp servers on any interface, the initiation of
215 # the dhcp server must be done after the wlan interfaces are figured
216 # out as opposed to being in __init__
217 self._dhcp = dhcp_server.DhcpServer(self.ssh, interface=interface)
218
219 # For multi bssid configurations the mac address
220 # of the wireless interface needs to have enough space to mask out
221 # up to 8 different mac addresses. The easiest way to do this
222 # is to set the last byte to 0. While technically this could
223 # cause a duplicate mac address it is unlikely and will allow for
Bindu Mahadev2ef0c3e2017-07-13 15:39:55 -0700224 # one radio to have up to 8 APs on the interface.
Joe Brennan3d00b2a2017-04-13 14:27:05 -0700225 interface_mac_orig = None
Bindu Mahadev2ef0c3e2017-07-13 15:39:55 -0700226 cmd = "ifconfig %s|grep ether|awk -F' ' '{print $2}'" % interface
227 interface_mac_orig = self.ssh.run(cmd)
228 hostapd_config.bssid = interface_mac_orig.stdout[:-1] + '0'
Joe Brennan88279af2017-02-15 18:11:53 -0800229
Christopher Wileyede81f02016-11-01 09:15:30 -0700230 if interface in self._aps:
231 raise ValueError('No WiFi interface available for AP on '
232 'channel %d' % hostapd_config.channel)
233
234 apd = hostapd.Hostapd(self.ssh, interface)
Joe Brennan88279af2017-02-15 18:11:53 -0800235 new_instance = _ApInstance(hostapd=apd, subnet=subnet)
Christopher Wileyede81f02016-11-01 09:15:30 -0700236 self._aps[interface] = new_instance
237
238 # Turn off the DHCP server, we're going to change its settings.
239 self._dhcp.stop()
240 # Clear all routes to prevent old routes from interfering.
241 self._route_cmd.clear_routes(net_interface=interface)
242
Joe Brennan88279af2017-02-15 18:11:53 -0800243 if hostapd_config.bss_lookup:
244 # The dhcp_bss dictionary is created to hold the key/value
245 # pair of the interface name and the ip scope that will be
246 # used for the particular interface. The a, b, c, d
247 # variables below are the octets for the ip address. The
248 # third octet is then incremented for each interface that
249 # is requested. This part is designed to bring up the
250 # hostapd interfaces and not the DHCP servers for each
251 # interface.
252 dhcp_bss = {}
253 counter = 1
254 for bss in hostapd_config.bss_lookup:
Bindu Mahadev2ef0c3e2017-07-13 15:39:55 -0700255 if interface_mac_orig:
Bindu Mahadeve57533d2018-05-22 16:35:03 -0700256 hostapd_config.bss_lookup[
257 bss].bssid = interface_mac_orig.stdout[:-1] + str(
258 counter)
Joe Brennan88279af2017-02-15 18:11:53 -0800259 self._route_cmd.clear_routes(net_interface=str(bss))
Qi Jiangef7de182017-12-05 14:56:08 -0800260 if interface is self.wlan_2g:
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800261 starting_ip_range = self._AP_2G_SUBNET_STR
Joe Brennan88279af2017-02-15 18:11:53 -0800262 else:
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800263 starting_ip_range = self._AP_5G_SUBNET_STR
Joe Brennan88279af2017-02-15 18:11:53 -0800264 a, b, c, d = starting_ip_range.split('.')
265 dhcp_bss[bss] = dhcp_config.Subnet(
Qi Jiangef7de182017-12-05 14:56:08 -0800266 ipaddress.ip_network('%s.%s.%s.%s' %
267 (a, b, str(int(c) + counter), d)))
Joe Brennan88279af2017-02-15 18:11:53 -0800268 counter = counter + 1
269
270 apd.start(hostapd_config, additional_parameters=additional_parameters)
271
272 # The DHCP serer requires interfaces to have ips and routes before
273 # the server will come up.
Christopher Wileyede81f02016-11-01 09:15:30 -0700274 interface_ip = ipaddress.ip_interface(
275 '%s/%s' % (subnet.router, subnet.network.netmask))
276 self._ip_cmd.set_ipv4_address(interface, interface_ip)
Joe Brennan88279af2017-02-15 18:11:53 -0800277 if hostapd_config.bss_lookup:
278 # This loop goes through each interface that was setup for
279 # hostapd and assigns the DHCP scopes that were defined but
280 # not used during the hostapd loop above. The k and v
281 # variables represent the interface name, k, and dhcp info, v.
282 for k, v in dhcp_bss.items():
283 bss_interface_ip = ipaddress.ip_interface(
markdr85a5e1a2017-07-17 14:11:34 -0700284 '%s/%s' % (dhcp_bss[k].router,
285 dhcp_bss[k].network.netmask))
Joe Brennan88279af2017-02-15 18:11:53 -0800286 self._ip_cmd.set_ipv4_address(str(k), bss_interface_ip)
Ang Li73697b32015-12-03 00:41:53 +0000287
Christopher Wileyede81f02016-11-01 09:15:30 -0700288 # Restart the DHCP server with our updated list of subnets.
Joe Brennan88279af2017-02-15 18:11:53 -0800289 configured_subnets = [x.subnet for x in self._aps.values()]
290 if hostapd_config.bss_lookup:
291 for k, v in dhcp_bss.items():
292 configured_subnets.append(v)
293
294 self._dhcp.start(config=dhcp_config.DhcpConfig(configured_subnets))
Benny Peake85f112a2016-10-07 19:41:49 -0700295
Qi Jiangef7de182017-12-05 14:56:08 -0800296 # The following three commands are needed to enable bridging between
297 # the WAN and LAN/WLAN ports. This means anyone connecting to the
298 # WLAN/LAN ports will be able to access the internet if the WAN port
299 # is connected to the internet.
300 self.ssh.run('iptables -t nat -F')
301 self.ssh.run(
302 'iptables -t nat -A POSTROUTING -o %s -j MASQUERADE' % self.wan)
303 self.ssh.run('echo 1 > /proc/sys/net/ipv4/ip_forward')
304
Christopher Wileyede81f02016-11-01 09:15:30 -0700305 return interface
Benny Peake85f112a2016-10-07 19:41:49 -0700306
Joe Brennan3d00b2a2017-04-13 14:27:05 -0700307 def get_bssid_from_ssid(self, ssid):
308 """Gets the BSSID from a provided SSID
309
310 Args:
311 ssid: An SSID string
Bindu Mahadev9bc52e62017-06-28 17:01:12 -0700312 Returns: The BSSID if on the AP or None if SSID could not be found.
Joe Brennan3d00b2a2017-04-13 14:27:05 -0700313 """
314
Qi Jiangef7de182017-12-05 14:56:08 -0800315 interfaces = [self.wlan_2g, self.wlan_5g, ssid]
Bindu Mahadev9bc52e62017-06-28 17:01:12 -0700316 # Get the interface name associated with the given ssid.
317 for interface in interfaces:
markdr85a5e1a2017-07-17 14:11:34 -0700318 cmd = "iw dev %s info|grep ssid|awk -F' ' '{print $2}'" % (
Bindu Mahadev9bc52e62017-06-28 17:01:12 -0700319 str(interface))
320 iw_output = self.ssh.run(cmd)
321 if 'command failed: No such device' in iw_output.stderr:
322 continue
323 else:
324 # If the configured ssid is equal to the given ssid, we found
325 # the right interface.
326 if iw_output.stdout == ssid:
markdr85a5e1a2017-07-17 14:11:34 -0700327 cmd = "iw dev %s info|grep addr|awk -F' ' '{print $2}'" % (
Bindu Mahadev9bc52e62017-06-28 17:01:12 -0700328 str(interface))
329 iw_output = self.ssh.run(cmd)
330 return iw_output.stdout
331 return None
Joe Brennan3d00b2a2017-04-13 14:27:05 -0700332
Benny Peake85f112a2016-10-07 19:41:49 -0700333 def stop_ap(self, identifier):
334 """Stops a running ap on this controller.
Ang Li73697b32015-12-03 00:41:53 +0000335
336 Args:
Benny Peake85f112a2016-10-07 19:41:49 -0700337 identifier: The identify of the ap that should be taken down.
Ang Li73697b32015-12-03 00:41:53 +0000338 """
Joe Brennan88279af2017-02-15 18:11:53 -0800339
Qi Jiang293bc992017-09-14 17:15:20 -0700340 if identifier not in list(self._aps.keys()):
markdrb629b322017-05-22 13:44:06 -0700341 raise ValueError('Invalid identifier %s given' % identifier)
Ang Li73697b32015-12-03 00:41:53 +0000342
Joe Brennan88279af2017-02-15 18:11:53 -0800343 instance = self._aps.get(identifier)
Ang Li73697b32015-12-03 00:41:53 +0000344
Christopher Wileyede81f02016-11-01 09:15:30 -0700345 instance.hostapd.stop()
346 self._dhcp.stop()
Benny Peake85f112a2016-10-07 19:41:49 -0700347 self._ip_cmd.clear_ipv4_addresses(identifier)
Ang Li73697b32015-12-03 00:41:53 +0000348
Benny Peake85f112a2016-10-07 19:41:49 -0700349 # DHCP server needs to refresh in order to tear down the subnet no
350 # longer being used. In the event that all interfaces are torn down
351 # then an exception gets thrown. We need to catch this exception and
352 # check that all interfaces should actually be down.
Joe Brennan88279af2017-02-15 18:11:53 -0800353 configured_subnets = [x.subnet for x in self._aps.values()]
Qi Jiangaa818ba2017-09-16 17:09:47 -0700354 del self._aps[identifier]
Christopher Wileyede81f02016-11-01 09:15:30 -0700355 if configured_subnets:
356 self._dhcp.start(dhcp_config.DhcpConfig(configured_subnets))
Benny Peake85f112a2016-10-07 19:41:49 -0700357
358 def stop_all_aps(self):
359 """Stops all running aps on this device."""
Joe Brennan88279af2017-02-15 18:11:53 -0800360
Benny Peake7336fa42017-08-17 19:30:35 -0700361 for ap in list(self._aps.keys()):
Joe Brennan88279af2017-02-15 18:11:53 -0800362 try:
363 self.stop_ap(ap)
364 except dhcp_server.NoInterfaceError as e:
365 pass
Benny Peake85f112a2016-10-07 19:41:49 -0700366
367 def close(self):
368 """Called to take down the entire access point.
369
370 When called will stop all aps running on this host, shutdown the dhcp
markdrb629b322017-05-22 13:44:06 -0700371 server, and stop the ssh connection.
Ang Li73697b32015-12-03 00:41:53 +0000372 """
Joe Brennan88279af2017-02-15 18:11:53 -0800373
374 if self._aps:
375 self.stop_all_aps()
markdr85a5e1a2017-07-17 14:11:34 -0700376 self.ssh.close()
Qi Jiangc3e87852017-10-04 22:45:52 -0700377
Qi Jiangef7de182017-12-05 14:56:08 -0800378 def generate_bridge_configs(self, channel):
Qi Jiangc3e87852017-10-04 22:45:52 -0700379 """Generate a list of configs for a bridge between LAN and WLAN.
380
381 Args:
382 channel: the channel WLAN interface is brought up on
383 iface_lan: the LAN interface to bridge
384 Returns:
385 configs: tuple containing iface_wlan, iface_lan and bridge_ip
386 """
387
388 if channel < 15:
Qi Jiangef7de182017-12-05 14:56:08 -0800389 iface_wlan = self.wlan_2g
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800390 subnet_str = self._AP_2G_SUBNET_STR
Qi Jiangc3e87852017-10-04 22:45:52 -0700391 else:
Qi Jiangef7de182017-12-05 14:56:08 -0800392 iface_wlan = self.wlan_5g
Qi Jiang4d8b7cb2018-02-06 23:13:44 -0800393 subnet_str = self._AP_5G_SUBNET_STR
Qi Jiangc3e87852017-10-04 22:45:52 -0700394
Qi Jiangef7de182017-12-05 14:56:08 -0800395 iface_lan = self.lan
Qi Jiangc3e87852017-10-04 22:45:52 -0700396
397 a, b, c, d = subnet_str.strip('/24').split('.')
398 bridge_ip = "%s.%s.%s.%s" % (a, b, c, BRIDGE_IP_LAST)
399
400 configs = (iface_wlan, iface_lan, bridge_ip)
401
402 return configs