1#!/usr/bin/env python3
2#
3# Copyright (C) 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# 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, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16
17from acts import asserts
18from acts.controllers.ap_lib import hostapd_ap_preset
19from acts.controllers.ap_lib import hostapd_bss_settings
20from acts.controllers.ap_lib import hostapd_constants
21from acts.controllers.ap_lib import hostapd_security
22
23from acts.test_utils.net.NetstackBaseTest import NetstackBaseTest
24
25from acts.utils import rand_ascii_str
26
27
28class NetstackIxiaTest(NetstackBaseTest):
29    def __init__(self, controllers):
30        NetstackBaseTest.__init__(self, controllers)
31
32    def setup_class(self):
33        self.log.info('Setup {cls}'.format(cls=type(self)))
34
35        if not self.fuchsia_devices:
36            self.log.error(
37                "NetstackFuchsiaTest Init: Not enough fuchsia devices.")
38        self.log.info("Running testbed setup with one fuchsia devices")
39        self.fuchsia_dev = self.fuchsia_devices[0]
40
41        # We want to bring up several 2GHz and 5GHz BSSes.
42        wifi_bands = ['2g', '5g']
43
44        # Currently AP_DEFAULT_CHANNEL_2G is 6
45        # and AP_DEFAULT_CHANNEL_5G is 36.
46        wifi_channels = [
47            hostapd_constants.AP_DEFAULT_CHANNEL_2G,
48            hostapd_constants.AP_DEFAULT_CHANNEL_5G
49        ]
50
51        # Each band will start up an Open BSS (security_mode=None)
52        # and a WPA2 BSS (security_mode=hostapd_constants.WPA2_STRING)
53        security_modes = [None, hostapd_constants.WPA2_STRING]
54
55        # All secure BSSes will use the same password.
56        wifi_password = rand_ascii_str(10)
57        self.log.info('Wi-Fi password for this test: {wifi_password}'.format(
58            wifi_password=wifi_password))
59        hostapd_configs = []
60        wifi_interfaces = {}
61        bss_settings = {}
62
63        # Build a configuration for each sub-BSSID
64        for band_index, wifi_band in enumerate(wifi_bands):
65            ssid_name = 'Ixia_{wifi_band}_#{bss_number}_{security_mode}'
66            bss_settings[wifi_band] = []
67
68            # Prepare the extra SSIDs.
69            for mode_index, security_mode in enumerate(security_modes):
70
71                # Skip the first SSID because we configure that separately.
72                # due to the way the APIs work.  This loop is only concerned
73                # with the sub-BSSIDs.
74                if mode_index == 0:
75                    continue
76
77                bss_name = ssid_name.format(wifi_band=wifi_band,
78                                            security_mode=security_mode,
79                                            bss_number=mode_index + 1)
80
81                bss_setting = hostapd_bss_settings.BssSettings(
82                    name=bss_name,
83                    ssid=bss_name,
84                    security=hostapd_security.Security(
85                        security_mode=security_mode, password=wifi_password))
86                bss_settings[wifi_band].append(bss_setting)
87
88            # This is the configuration for the first SSID.
89            ssid_name = ssid_name.format(wifi_band=wifi_band,
90                                         security_mode=security_modes[0],
91                                         bss_number=1)
92
93            hostapd_configs.append(
94                hostapd_ap_preset.create_ap_preset(
95                    profile_name='whirlwind',
96                    iface_wlan_2g='wlan0',
97                    iface_wlan_5g='wlan1',
98                    ssid=ssid_name,
99                    channel=wifi_channels[band_index],
100                    security=hostapd_security.Security(
101                        security_mode=security_modes[0],
102                        password=wifi_password),
103                    bss_settings=bss_settings[wifi_band]))
104
105            access_point = self.access_points[band_index]
106
107            # Now bring up the AP and track the interfaces we're using for
108            # each BSSID.  All BSSIDs are now beaconing.
109            wifi_interfaces[wifi_band] = access_point.start_ap(
110                hostapd_configs[band_index])
111
112            # Disable DHCP on this Wi-Fi band.
113            # Note: This also disables DHCP on each sub-BSSID due to how
114            # the APIs are built.
115            #
116            # We need to do this in order to enable IxANVL testing across
117            # Wi-Fi, which needs to configure the IP addresses per-interface
118            # on the client device.
119            access_point.stop_dhcp()
120
121            # Disable NAT.
122            # NAT config in access_point.py is global at the moment, but
123            # calling it twice (once per band) won't hurt anything.  This is
124            # easier than trying to conditionalize per band.
125            #
126            # Note that we could make this per-band, but it would require
127            # refactoring the access_point.py code that turns on NAT, however
128            # if that ever does happen then this code will work as expected
129            # without modification.
130            #
131            # This is also required for IxANVL testing.  NAT would interfere
132            # with IxANVL because IxANVL needs to see the raw frames
133            # sourcing/sinking from/to the DUT for protocols such as ARP and
134            # DHCP, but it also needs the MAC/IP of the source and destination
135            # frames and packets to be from the DUT, so we want the AP to act
136            # like a bridge for these tests.
137            access_point.stop_nat()
138
139        # eth1 is the LAN port, which will always be a part of the bridge.
140        bridge_interfaces = ['eth1']
141
142        # This adds each bssid interface to the bridge.
143        for wifi_band in wifi_bands:
144            for wifi_interface in wifi_interfaces[wifi_band]:
145                bridge_interfaces.append(wifi_interface)
146
147        # Each interface can only be a member of 1 bridge, so we're going to use
148        # the last access_point object to set the bridge up for all interfaces.
149        access_point.create_bridge(bridge_name='ixia_bridge0',
150                                   interfaces=bridge_interfaces)
151
152    def setup_test(self):
153        pass
154
155    def teardown_test(self):
156        pass
157
158    def teardown_class(self):
159        self.log.info('Teardown {cls}'.format(cls=type(self)))
160
161        import pdb
162        pdb.set_trace()
163
164        for access_point in self.access_points:
165            access_point.remove_bridge(bridge_name='ixia_bridge0')
166
167    """Tests"""
168    def test_do_nothing(self):
169        return True
170