1#!/usr/bin/env python3
2#
3#   Copyright 2019 - 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 itertools
18import re
19
20from acts import utils
21from acts.controllers.ap_lib.hostapd_security import Security
22from acts.controllers.ap_lib import hostapd_constants
23from acts.controllers.ap_lib import hostapd_config
24from acts.test_utils.abstract_devices.wlan_device import create_wlan_device
25from acts.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
26from acts.test_utils.abstract_devices.utils_lib.wlan_utils import validate_setup_ap_and_associate
27from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
28from acts.utils import rand_ascii_str
29
30FREQUENCY_24 = ['2.4GHz']
31FREQUENCY_5 = ['5GHz']
32CHANNEL_BANDWIDTH_20 = ['HT20']
33CHANNEL_BANDWIDTH_40_LOWER = ['HT40-']
34CHANNEL_BANDWIDTH_40_UPPER = ['HT40+']
35SECURITY_OPEN = 'open'
36SECURITY_WPA2 = 'wpa2'
37LDPC = [hostapd_constants.N_CAPABILITY_LDPC, '']
38TX_STBC = [hostapd_constants.N_CAPABILITY_TX_STBC, '']
39RX_STBC = [hostapd_constants.N_CAPABILITY_RX_STBC1, '']
40SGI_20 = [hostapd_constants.N_CAPABILITY_SGI20, '']
41SGI_40 = [hostapd_constants.N_CAPABILITY_SGI40, '']
42DSSS_CCK = [hostapd_constants.N_CAPABILITY_DSSS_CCK_40, '']
43INTOLERANT_40 = [hostapd_constants.N_CAPABILITY_40_INTOLERANT, '']
44MAX_AMPDU_7935 = [hostapd_constants.N_CAPABILITY_MAX_AMSDU_7935, '']
45SMPS = [hostapd_constants.N_CAPABILITY_SMPS_STATIC, '']
46
47
48def generate_test_name(settings):
49    """Generates a string based on the n_capabilities for a test case
50
51    Args:
52        settings: A dictionary of hostapd constant n_capabilities.
53
54    Returns:
55        A string that represents a test case name.
56    """
57    ret = []
58    for cap in hostapd_constants.N_CAPABILITIES_MAPPING.keys():
59        if cap in settings['n_capabilities']:
60            ret.append(hostapd_constants.N_CAPABILITIES_MAPPING[cap])
61    return '%s_%s_%s_%s' % (settings['frequency'], settings['chbw'],
62                            settings['security'], ''.join(ret))
63
64
65class WlanPhyCompliance11NTest(AbstractDeviceWlanDeviceBaseTest):
66    """Tests for validating 11n PHYS.
67
68    Test Bed Requirement:
69    * One Android device or Fuchsia device
70    * One Access Point
71    """
72    def __init__(self, controllers):
73        WifiBaseTest.__init__(self, controllers)
74        self.tests = [
75            'test_11n_capabilities_24_HT20',
76            'test_11n_capabilities_24_HT40_lower',
77            'test_11n_capabilities_24_HT40_upper',
78            'test_11n_capabilities_5_HT20',
79            'test_11n_capabilities_5_HT40_lower',
80            'test_11n_capabilities_5_HT40_upper',
81            'test_11n_capabilities_24_HT20_wpa2',
82            'test_11n_capabilities_24_HT40_lower_wpa2',
83            'test_11n_capabilities_24_HT40_upper_wpa2',
84            'test_11n_capabilities_5_HT20_wpa2',
85            'test_11n_capabilities_5_HT40_lower_wpa2',
86            'test_11n_capabilities_5_HT40_upper_wpa2'
87        ]
88        if 'debug_11n_tests' in self.user_params:
89            self.tests.append('test_11n_capabilities_debug')
90
91    def setup_class(self):
92        super().setup_class()
93        if 'dut' in self.user_params:
94            if self.user_params['dut'] == 'fuchsia_devices':
95                self.dut = create_wlan_device(self.fuchsia_devices[0])
96            elif self.user_params['dut'] == 'android_devices':
97                self.dut = create_wlan_device(self.android_devices[0])
98            else:
99                raise ValueError('Invalid DUT specified in config. (%s)' %
100                                 self.user_params['dut'])
101        else:
102            # Default is an android device, just like the other tests
103            self.dut = create_wlan_device(self.android_devices[0])
104
105        self.access_point = self.access_points[0]
106        self.access_point.stop_all_aps()
107
108    def setup_test(self):
109        if hasattr(self, "android_devices"):
110            for ad in self.android_devices:
111                ad.droid.wakeLockAcquireBright()
112                ad.droid.wakeUpNow()
113        self.dut.wifi_toggle_state(True)
114
115    def teardown_test(self):
116        if hasattr(self, "android_devices"):
117            for ad in self.android_devices:
118                ad.droid.wakeLockRelease()
119                ad.droid.goToSleepNow()
120        self.dut.turn_location_off_and_scan_toggle_off()
121        self.dut.disconnect()
122        self.dut.reset_wifi()
123        self.access_point.stop_all_aps()
124
125    def on_fail(self, test_name, begin_time):
126        super().on_fail(test_name, begin_time)
127        self.access_point.stop_all_aps()
128
129    def setup_and_connect(self, ap_settings):
130        """Generates a hostapd config, setups up the AP with that config, then
131           attempts to associate a DUT
132
133        Args:
134               ap_settings: A dictionary of hostapd constant n_capabilities.
135        """
136        security_profile = None
137        password = None
138        temp_n_capabilities = list(ap_settings['n_capabilities'])
139        n_capabilities = []
140        for n_capability in temp_n_capabilities:
141            if n_capability in hostapd_constants.N_CAPABILITIES_MAPPING.keys():
142                n_capabilities.append(n_capability)
143
144        if ap_settings['chbw'] == 'HT20' or ap_settings['chbw'] == 'HT40+':
145            if ap_settings['frequency'] == '2.4GHz':
146                channel = 1
147            elif ap_settings['frequency'] == '5GHz':
148                channel = 36
149            else:
150                raise ValueError('Invalid frequence: %s' %
151                                 ap_settings['frequency'])
152
153        if ap_settings['chbw'] == 'HT40-':
154            if ap_settings['frequency'] == '2.4GHz':
155                channel = 11
156            elif ap_settings['frequency'] == '5GHz':
157                channel = 60
158            else:
159                raise ValueError('Invalid frequency: %s' %
160                                 ap_settings['frequency'])
161
162        if ap_settings['chbw'] == 'HT40-' or ap_settings['chbw'] == 'HT40+':
163            if hostapd_config.ht40_plus_allowed(channel):
164                extended_channel = hostapd_constants.N_CAPABILITY_HT40_PLUS
165            elif hostapd_config.ht40_minus_allowed(channel):
166                extended_channel = hostapd_constants.N_CAPABILITY_HT40_MINUS
167            else:
168                raise ValueError('Invalid channel: %s' % channel)
169            n_capabilities.append(extended_channel)
170
171        if ap_settings['security'] == 'wpa2':
172            security_profile = Security(security_mode=SECURITY_WPA2,
173                                        password=rand_ascii_str(20),
174                                        wpa_cipher='CCMP',
175                                        wpa2_cipher='CCMP')
176            password = security_profile.password
177
178        validate_setup_ap_and_associate(access_point=self.access_point,
179                                        client=self.dut,
180                                        profile_name='whirlwind',
181                                        mode=hostapd_constants.MODE_11N_MIXED,
182                                        channel=channel,
183                                        n_capabilities=n_capabilities,
184                                        ac_capabilities=[],
185                                        force_wmm=True,
186                                        ssid=utils.rand_ascii_str(20),
187                                        security=security_profile,
188                                        password=password)
189
190    def test_11n_capabilities_24_HT20(self):
191        test_list = []
192        for combination in itertools.product(FREQUENCY_24,
193                                             CHANNEL_BANDWIDTH_20, LDPC,
194                                             TX_STBC, RX_STBC, SGI_20,
195                                             INTOLERANT_40, MAX_AMPDU_7935,
196                                             SMPS):
197            test_frequency = combination[0]
198            test_chbw = combination[1]
199            n_capabilities = combination[2:]
200            test_list.append({
201                'frequency': test_frequency,
202                'chbw': test_chbw,
203                'security': SECURITY_OPEN,
204                'n_capabilities': n_capabilities
205            })
206        self.run_generated_testcases(self.setup_and_connect,
207                                     settings=test_list,
208                                     name_func=generate_test_name)
209
210    def test_11n_capabilities_24_HT40_lower(self):
211        test_list = []
212        for combination in itertools.product(FREQUENCY_24,
213                                             CHANNEL_BANDWIDTH_40_LOWER, LDPC,
214                                             TX_STBC, RX_STBC, SGI_20, SGI_40,
215                                             MAX_AMPDU_7935, SMPS, DSSS_CCK):
216            test_frequency = combination[0]
217            test_chbw = combination[1]
218            n_capabilities = combination[2:]
219            test_list.append({
220                'frequency': test_frequency,
221                'chbw': test_chbw,
222                'security': SECURITY_OPEN,
223                'n_capabilities': n_capabilities
224            })
225        self.run_generated_testcases(self.setup_and_connect,
226                                     settings=test_list,
227                                     name_func=generate_test_name)
228
229    def test_11n_capabilities_24_HT40_upper(self):
230        test_list = []
231        for combination in itertools.product(FREQUENCY_24,
232                                             CHANNEL_BANDWIDTH_40_UPPER, LDPC,
233                                             TX_STBC, RX_STBC, SGI_20, SGI_40,
234                                             MAX_AMPDU_7935, SMPS, DSSS_CCK):
235            test_frequency = combination[0]
236            test_chbw = combination[1]
237            n_capabilities = combination[2:]
238            test_list.append({
239                'frequency': test_frequency,
240                'chbw': test_chbw,
241                'security': SECURITY_OPEN,
242                'n_capabilities': n_capabilities
243            })
244        self.run_generated_testcases(self.setup_and_connect,
245                                     settings=test_list,
246                                     name_func=generate_test_name)
247
248    def test_11n_capabilities_5_HT20(self):
249        test_list = []
250        for combination in itertools.product(FREQUENCY_5, CHANNEL_BANDWIDTH_20,
251                                             LDPC, TX_STBC, RX_STBC, SGI_20,
252                                             INTOLERANT_40, MAX_AMPDU_7935,
253                                             SMPS):
254            test_frequency = combination[0]
255            test_chbw = combination[1]
256            n_capabilities = combination[2:]
257            test_list.append({
258                'frequency': test_frequency,
259                'chbw': test_chbw,
260                'security': SECURITY_OPEN,
261                'n_capabilities': n_capabilities
262            })
263        self.run_generated_testcases(self.setup_and_connect,
264                                     settings=test_list,
265                                     name_func=generate_test_name)
266
267    def test_11n_capabilities_5_HT40_lower(self):
268        test_list = []
269        for combination in itertools.product(FREQUENCY_5,
270                                             CHANNEL_BANDWIDTH_40_LOWER, LDPC,
271                                             TX_STBC, RX_STBC, SGI_20, SGI_40,
272                                             MAX_AMPDU_7935, SMPS, DSSS_CCK):
273            test_frequency = combination[0]
274            test_chbw = combination[1]
275            n_capabilities = combination[2:]
276            test_list.append({
277                'frequency': test_frequency,
278                'chbw': test_chbw,
279                'security': SECURITY_OPEN,
280                'n_capabilities': n_capabilities
281            })
282        self.run_generated_testcases(self.setup_and_connect,
283                                     settings=test_list,
284                                     name_func=generate_test_name)
285
286    def test_11n_capabilities_5_HT40_upper(self):
287        test_list = []
288        for combination in itertools.product(FREQUENCY_5,
289                                             CHANNEL_BANDWIDTH_40_UPPER, LDPC,
290                                             TX_STBC, RX_STBC, SGI_20, SGI_40,
291                                             MAX_AMPDU_7935, SMPS, DSSS_CCK):
292            test_frequency = combination[0]
293            test_chbw = combination[1]
294            n_capabilities = combination[2:]
295            test_list.append({
296                'frequency': test_frequency,
297                'chbw': test_chbw,
298                'security': SECURITY_OPEN,
299                'n_capabilities': n_capabilities
300            })
301        self.run_generated_testcases(self.setup_and_connect,
302                                     settings=test_list,
303                                     name_func=generate_test_name)
304
305    def test_11n_capabilities_24_HT20_wpa2(self):
306        test_list = []
307        for combination in itertools.product(FREQUENCY_24,
308                                             CHANNEL_BANDWIDTH_20, LDPC,
309                                             TX_STBC, RX_STBC, SGI_20,
310                                             INTOLERANT_40, MAX_AMPDU_7935,
311                                             SMPS):
312            test_frequency = combination[0]
313            test_chbw = combination[1]
314            n_capabilities = combination[2:]
315            test_list.append({
316                'frequency': test_frequency,
317                'chbw': test_chbw,
318                'security': SECURITY_WPA2,
319                'n_capabilities': n_capabilities
320            })
321        self.run_generated_testcases(self.setup_and_connect,
322                                     settings=test_list,
323                                     name_func=generate_test_name)
324
325    def test_11n_capabilities_24_HT40_lower_wpa2(self):
326        test_list = []
327        for combination in itertools.product(FREQUENCY_24,
328                                             CHANNEL_BANDWIDTH_40_LOWER, LDPC,
329                                             TX_STBC, RX_STBC, SGI_20, SGI_40,
330                                             MAX_AMPDU_7935, SMPS, DSSS_CCK):
331            test_frequency = combination[0]
332            test_chbw = combination[1]
333            n_capabilities = combination[2:]
334            test_list.append({
335                'frequency': test_frequency,
336                'chbw': test_chbw,
337                'security': SECURITY_WPA2,
338                'n_capabilities': n_capabilities
339            })
340        self.run_generated_testcases(self.setup_and_connect,
341                                     settings=test_list,
342                                     name_func=generate_test_name)
343
344    def test_11n_capabilities_24_HT40_upper_wpa2(self):
345        test_list = []
346        for combination in itertools.product(FREQUENCY_24,
347                                             CHANNEL_BANDWIDTH_40_UPPER, LDPC,
348                                             TX_STBC, RX_STBC, SGI_20, SGI_40,
349                                             MAX_AMPDU_7935, SMPS, DSSS_CCK):
350            test_frequency = combination[0]
351            test_chbw = combination[1]
352            n_capabilities = combination[2:]
353            test_list.append({
354                'frequency': test_frequency,
355                'chbw': test_chbw,
356                'security': SECURITY_WPA2,
357                'n_capabilities': n_capabilities
358            })
359        self.run_generated_testcases(self.setup_and_connect,
360                                     settings=test_list,
361                                     name_func=generate_test_name)
362
363    def test_11n_capabilities_5_HT20_wpa2(self):
364        test_list = []
365        for combination in itertools.product(FREQUENCY_5, CHANNEL_BANDWIDTH_20,
366                                             LDPC, TX_STBC, RX_STBC, SGI_20,
367                                             INTOLERANT_40, MAX_AMPDU_7935,
368                                             SMPS):
369            test_frequency = combination[0]
370            test_chbw = combination[1]
371            n_capabilities = combination[2:]
372            test_list.append({
373                'frequency': test_frequency,
374                'chbw': test_chbw,
375                'security': SECURITY_WPA2,
376                'n_capabilities': n_capabilities
377            })
378        self.run_generated_testcases(self.setup_and_connect,
379                                     settings=test_list,
380                                     name_func=generate_test_name)
381
382    def test_11n_capabilities_5_HT40_lower_wpa2(self):
383        test_list = []
384        for combination in itertools.product(FREQUENCY_5,
385                                             CHANNEL_BANDWIDTH_40_LOWER, LDPC,
386                                             TX_STBC, RX_STBC, SGI_20, SGI_40,
387                                             MAX_AMPDU_7935, SMPS, DSSS_CCK):
388            test_frequency = combination[0]
389            test_chbw = combination[1]
390            n_capabilities = combination[2:]
391            test_list.append({
392                'frequency': test_frequency,
393                'chbw': test_chbw,
394                'security': SECURITY_WPA2,
395                'n_capabilities': n_capabilities
396            })
397        self.run_generated_testcases(self.setup_and_connect,
398                                     settings=test_list,
399                                     name_func=generate_test_name)
400
401    def test_11n_capabilities_5_HT40_upper_wpa2(self):
402        test_list = []
403        for combination in itertools.product(FREQUENCY_5,
404                                             CHANNEL_BANDWIDTH_40_UPPER, LDPC,
405                                             TX_STBC, RX_STBC, SGI_20, SGI_40,
406                                             MAX_AMPDU_7935, SMPS, DSSS_CCK):
407            test_frequency = combination[0]
408            test_chbw = combination[1]
409            n_capabilities = combination[2:]
410            test_list.append({
411                'frequency': test_frequency,
412                'chbw': test_chbw,
413                'security': SECURITY_WPA2,
414                'n_capabilities': n_capabilities
415            })
416        self.run_generated_testcases(self.setup_and_connect,
417                                     settings=test_list,
418                                     name_func=generate_test_name)
419
420    def test_11n_capabilities_debug(self):
421        allowed_frequencies = FREQUENCY_5 + FREQUENCY_24
422        allowed_chbw = (CHANNEL_BANDWIDTH_20 + CHANNEL_BANDWIDTH_40_LOWER +
423                        CHANNEL_BANDWIDTH_40_UPPER)
424        allowed_security = [SECURITY_WPA2, SECURITY_OPEN]
425        freq_chbw_sec = re.compile(r'(.*)_(.*)_(.*)_(\[.*\])?$')
426        for test_title in self.user_params['debug_11n_tests']:
427            test_list = []
428            test_to_run = re.match(freq_chbw_sec, test_title)
429            if test_to_run:
430                test_frequency = test_to_run.group(1)
431                test_chbw = test_to_run.group(2)
432                security = test_to_run.group(3)
433                if (test_frequency in allowed_frequencies
434                        and test_chbw in allowed_chbw
435                        and security in allowed_security):
436                    if test_to_run.group(4):
437                        n_capabilities_str = test_to_run.group(4)
438                    else:
439                        n_capabilities_str = ''
440                    n_capabilities_list = []
441                    if '[LDPC]' in n_capabilities_str:
442                        n_capabilities_list.append(
443                            hostapd_constants.N_CAPABILITY_LDPC)
444                    if '[TX-STBC]' in n_capabilities_str:
445                        n_capabilities_list.append(
446                            hostapd_constants.N_CAPABILITY_TX_STBC)
447                    if '[RX-STBC1]' in n_capabilities_str:
448                        n_capabilities_list.append(
449                            hostapd_constants.N_CAPABILITY_RX_STBC1)
450                    if '[SHORT-GI-20]' in n_capabilities_str:
451                        n_capabilities_list.append(
452                            hostapd_constants.N_CAPABILITY_SGI20)
453                    if '[SHORT-GI-40]' in n_capabilities_str:
454                        n_capabilities_list.append(
455                            hostapd_constants.N_CAPABILITY_SGI40)
456                    if '[DSSS_CCK-40]' in n_capabilities_str:
457                        n_capabilities_list.append(
458                            hostapd_constants.N_CAPABILITY_DSSS_CCK_40)
459                    if '[40-INTOLERANT]' in n_capabilities_str:
460                        n_capabilities_list.append(
461                            hostapd_constants.N_CAPABILITY_40_INTOLERANT)
462                    if '[MAX-AMSDU-7935]' in n_capabilities_str:
463                        n_capabilities_list.append(
464                            hostapd_constants.N_CAPABILITY_MAX_AMSDU_7935)
465                    if '[SMPS-STATIC]' in n_capabilities_str:
466                        n_capabilities_list.append(
467                            hostapd_constants.N_CAPABILITY_SMPS_STATIC)
468                    n_capabilities = tuple(n_capabilities_list)
469                    test_list.append({
470                        'frequency': test_frequency,
471                        'chbw': test_chbw,
472                        'security': security,
473                        'n_capabilities': n_capabilities
474                    })
475                    self.run_generated_testcases(self.setup_and_connect,
476                                                 settings=test_list,
477                                                 name_func=generate_test_name)
478                else:
479                    self.log.error('Invalid test (%s). Trying the next one.' %
480                                   test_title)
481            else:
482                self.log.error('Invalid test (%s). Trying the next one.' %
483                               test_title)
484