1#!/usr/bin/python3.4
2#
3#   Copyright 2017 - The Android Open Source Project
4#
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
17import time
18
19from acts import asserts
20from acts.test_decorators import test_tracker_info
21from acts.test_utils.net import connectivity_const as cconsts
22from acts.test_utils.wifi.aware import aware_const as aconsts
23from acts.test_utils.wifi.aware import aware_test_utils as autils
24from acts.test_utils.wifi.aware.AwareBaseTest import AwareBaseTest
25
26
27class MacRandomTest(AwareBaseTest):
28    """Set of tests for Wi-Fi Aware MAC address randomization of NMI (NAN
29  management interface) and NDI (NAN data interface)."""
30
31    NUM_ITERATIONS = 10
32
33    # number of second to 'reasonably' wait to make sure that devices synchronize
34    # with each other - useful for OOB test cases, where the OOB discovery would
35    # take some time
36    WAIT_FOR_CLUSTER = 5
37
38    def request_network(self, dut, ns):
39        """Request a Wi-Fi Aware network.
40
41    Args:
42      dut: Device
43      ns: Network specifier
44    Returns: the request key
45    """
46        network_req = {"TransportType": 5, "NetworkSpecifier": ns}
47        return dut.droid.connectivityRequestWifiAwareNetwork(network_req)
48
49    ##########################################################################
50
51    @test_tracker_info(uuid="09964368-146a-48e4-9f33-6a319f9eeadc")
52    def test_nmi_ndi_randomization_on_enable(self):
53        """Validate randomization of the NMI (NAN management interface) and all NDIs
54    (NAN data-interface) on each enable/disable cycle"""
55        dut = self.android_devices[0]
56
57        # re-enable randomization interval (since if disabled it may also disable
58        # the 'randomize on enable' feature).
59        autils.configure_mac_random_interval(dut, 1800)
60
61        # DUT: attach and wait for confirmation & identity 10 times
62        mac_addresses = {}
63        for i in range(self.NUM_ITERATIONS):
64            id = dut.droid.wifiAwareAttach(True)
65            autils.wait_for_event(dut, aconsts.EVENT_CB_ON_ATTACHED)
66            ident_event = autils.wait_for_event(
67                dut, aconsts.EVENT_CB_ON_IDENTITY_CHANGED)
68
69            # process NMI
70            mac = ident_event["data"]["mac"]
71            dut.log.info("NMI=%s", mac)
72            if mac in mac_addresses:
73                mac_addresses[mac] = mac_addresses[mac] + 1
74            else:
75                mac_addresses[mac] = 1
76
77            # process NDIs
78            time.sleep(5)  # wait for NDI creation to complete
79            for j in range(
80                    dut.aware_capabilities[aconsts.CAP_MAX_NDI_INTERFACES]):
81                ndi_interface = "%s%d" % (aconsts.AWARE_NDI_PREFIX, j)
82                ndi_mac = autils.get_mac_addr(dut, ndi_interface)
83                dut.log.info("NDI %s=%s", ndi_interface, ndi_mac)
84                if ndi_mac in mac_addresses:
85                    mac_addresses[ndi_mac] = mac_addresses[ndi_mac] + 1
86                else:
87                    mac_addresses[ndi_mac] = 1
88
89            dut.droid.wifiAwareDestroy(id)
90
91        # Test for uniqueness
92        for mac in mac_addresses.keys():
93            if mac_addresses[mac] != 1:
94                asserts.fail("MAC address %s repeated %d times (all=%s)" %
95                             (mac, mac_addresses[mac], mac_addresses))
96
97        # Verify that infra interface (e.g. wlan0) MAC address is not used for NMI
98        infra_mac = autils.get_wifi_mac_address(dut)
99        asserts.assert_false(
100            infra_mac in mac_addresses,
101            "Infrastructure MAC address (%s) is used for Aware NMI (all=%s)" %
102            (infra_mac, mac_addresses))
103
104    @test_tracker_info(uuid="0fb0b5d8-d9cb-4e37-b9af-51811be5670d")
105    def test_nmi_randomization_on_interval(self):
106        """Validate randomization of the NMI (NAN management interface) on a set
107    interval. Default value is 30 minutes - change to a small value to allow
108    testing in real-time"""
109        RANDOM_INTERVAL = 120  # minimal value in current implementation
110
111        dut = self.android_devices[0]
112
113        # set randomization interval to 120 seconds
114        autils.configure_mac_random_interval(dut, RANDOM_INTERVAL)
115
116        # attach and wait for first identity
117        id = dut.droid.wifiAwareAttach(True)
118        autils.wait_for_event(dut, aconsts.EVENT_CB_ON_ATTACHED)
119        ident_event = autils.wait_for_event(
120            dut, aconsts.EVENT_CB_ON_IDENTITY_CHANGED)
121        mac1 = ident_event["data"]["mac"]
122
123        # wait for second identity callback
124        # Note: exact randomization interval is not critical, just approximate,
125        # hence giving a few more seconds.
126        ident_event = autils.wait_for_event(
127            dut,
128            aconsts.EVENT_CB_ON_IDENTITY_CHANGED,
129            timeout=RANDOM_INTERVAL + 5)
130        mac2 = ident_event["data"]["mac"]
131
132        # validate MAC address is randomized
133        asserts.assert_false(
134            mac1 == mac2,
135            "Randomized MAC addresses (%s, %s) should be different" % (mac1,
136                                                                       mac2))
137
138        # clean-up
139        dut.droid.wifiAwareDestroy(id)
140