1#!/usr/bin/env python3
2#
3#   Copyright 2019 - The Android secure 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.
16import os
17import time
18
19from acts import asserts
20from acts import context
21from acts.controllers.access_point import setup_ap
22from acts.controllers.ap_lib import hostapd_constants
23from acts.controllers.ap_lib.radvd import Radvd
24from acts.controllers.ap_lib import radvd_constants
25from acts.controllers.ap_lib.radvd_config import RadvdConfig
26from acts.controllers.ap_lib.hostapd_security import Security
27from acts.controllers.attenuator import get_attenuators_for_device
28from acts.controllers.iperf_server import IPerfResult
29from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
30from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
31from acts.utils import rand_ascii_str
32
33from bokeh.plotting import ColumnDataSource
34from bokeh.plotting import figure
35from bokeh.plotting import output_file
36from bokeh.plotting import save
37
38AP_11ABG_PROFILE_NAME = 'whirlwind_11ag_legacy'
39REPORTING_SPEED_UNITS = 'Mbps'
40
41RVR_GRAPH_SUMMARY_FILE = 'rvr_summary.html'
42
43DAD_TIMEOUT_SEC = 30
44
45
46def create_rvr_graph(test_name, graph_path, graph_data):
47    """Creates the RvR graphs
48    Args:
49        test_name: The name of test that was run.  This is the title of the
50            graph
51        graph_path: Where to put the graph html file.
52        graph_data: A dictionary of the data to be graphed.
53    Returns:
54        A list of bokeh graph objects.
55        """
56    output_file('%srvr_throughput_vs_attn_%s.html' % (graph_path, test_name),
57                title=test_name)
58    throughput_vs_attn_data = ColumnDataSource(data=dict(
59        relative_attn=graph_data['throughput_vs_attn']['relative_attn'],
60        throughput=graph_data['throughput_vs_attn']['throughput']))
61    TOOLTIPS = [("Attenuation", "@relative_attn"),
62                ("Throughput", "@throughput")]
63    throughput_vs_attn_graph = figure(
64        title="Throughput vs Relative Attenuation (Test Case: %s)" % test_name,
65        x_axis_label=graph_data['throughput_vs_attn']['x_label'],
66        y_axis_label=graph_data['throughput_vs_attn']['y_label'],
67        x_range=graph_data['throughput_vs_attn']['relative_attn'],
68        tooltips=TOOLTIPS)
69    throughput_vs_attn_graph.sizing_mode = 'stretch_width'
70    throughput_vs_attn_graph.title.align = 'center'
71    throughput_vs_attn_graph.line('relative_attn',
72                                  'throughput',
73                                  source=throughput_vs_attn_data,
74                                  line_width=2)
75    throughput_vs_attn_graph.circle('relative_attn',
76                                    'throughput',
77                                    source=throughput_vs_attn_data,
78                                    size=10)
79    save([throughput_vs_attn_graph])
80    return [throughput_vs_attn_graph]
81
82
83def write_csv_rvr_data(test_name, csv_path, csv_data):
84    """Writes the CSV data for the RvR test
85    Args:
86        test_name: The name of test that was run.
87        csv_path: Where to put the csv file.
88        csv_data: A dictionary of the data to be put in the csv file.
89    """
90    csv_file_name = '%srvr_throughput_vs_attn_%s.csv' % (csv_path, test_name)
91    throughput = csv_data['throughput_vs_attn']['throughput']
92    relative_attn = csv_data['throughput_vs_attn']['relative_attn']
93    with open(csv_file_name, 'w+') as csv_fileId:
94        csv_fileId.write('%s,%s\n' %
95                         (csv_data['throughput_vs_attn']['x_label'],
96                          csv_data['throughput_vs_attn']['y_label']))
97        for csv_loop_counter in range(0, len(relative_attn)):
98            csv_fileId.write('%s,%s\n' % (int(relative_attn[csv_loop_counter]),
99                                          throughput[csv_loop_counter]))
100
101
102class WlanRvrTest(WifiBaseTest):
103    """Tests running WLAN RvR.
104
105    Test Bed Requirement:
106    * One Android device or Fuchsia device
107    * One Access Point
108    * One attenuator
109    * One Linux iPerf Server
110    """
111
112    def __init__(self, controllers):
113        super().__init__(controllers)
114        self.rvr_graph_summary = []
115
116    def setup_class(self):
117        super().setup_class()
118        if 'dut' in self.user_params:
119            if self.user_params['dut'] == 'fuchsia_devices':
120                self.dut = create_wlan_device(self.fuchsia_devices[0])
121            elif self.user_params['dut'] == 'android_devices':
122                self.dut = create_wlan_device(self.android_devices[0])
123            else:
124                raise ValueError('Invalid DUT specified in config. (%s)' %
125                                 self.user_params['dut'])
126        else:
127            # Default is an android device, just like the other tests
128            self.dut = create_wlan_device(self.android_devices[0])
129
130        self.starting_attn = (self.user_params['rvr_settings'].get(
131            'starting_attn', 0))
132
133        self.ending_attn = (self.user_params['rvr_settings'].get(
134            'ending_attn', 95))
135
136        self.step_size_in_db = (self.user_params['rvr_settings'].get(
137            'step_size_in_db', 1))
138
139        self.dwell_time_in_secs = (self.user_params['rvr_settings'].get(
140            'dwell_time_in_secs', 10))
141
142        self.reverse_rvr_after_forward = bool(
143            (self.user_params['rvr_settings'].get('reverse_rvr_after_forward',
144                                                  None)))
145
146        self.iperf_flags = (self.user_params['rvr_settings'].get(
147            'iperf_flags', '-i 1'))
148
149        self.iperf_flags = '%s -t %s -J' % (self.iperf_flags,
150                                            self.dwell_time_in_secs)
151
152        self.debug_loop_count = (self.user_params['rvr_settings'].get(
153            'debug_loop_count', 1))
154
155        self.debug_pre_traffic_cmd = (self.user_params['rvr_settings'].get(
156            'debug_pre_traffic_cmd', None))
157
158        self.debug_post_traffic_cmd = (self.user_params['rvr_settings'].get(
159            'debug_post_traffic_cmd', None))
160
161        self.router_adv_daemon = None
162
163        if self.ending_attn == 'auto':
164            self.use_auto_end = True
165            self.ending_attn = 100
166            if self.step_size_in_db > 2:
167                asserts.fail('When using an ending attenuation of \'auto\' '
168                             'please use a value < 2db.  Larger jumps will '
169                             'break the test reporting.')
170
171        self.access_point = self.access_points[0]
172        self.attenuators_2g = get_attenuators_for_device(
173            self.controller_configs['AccessPoint'][0]['Attenuator'],
174            self.attenuators, 'attenuator_ports_wifi_2g')
175        self.attenuators_5g = get_attenuators_for_device(
176            self.controller_configs['AccessPoint'][0]['Attenuator'],
177            self.attenuators, 'attenuator_ports_wifi_5g')
178
179        self.iperf_server = self.iperf_servers[0]
180
181        if hasattr(self, "iperf_clients") and self.iperf_clients:
182            self.dut_iperf_client = self.iperf_clients[0]
183        else:
184            self.dut_iperf_client = self.dut.create_iperf_client()
185
186        self.access_point.stop_all_aps()
187
188    def setup_test(self):
189        if self.iperf_server:
190            self.iperf_server.start()
191        if hasattr(self, "android_devices"):
192            for ad in self.android_devices:
193                ad.droid.wakeLockAcquireBright()
194                ad.droid.wakeUpNow()
195        self.dut.wifi_toggle_state(True)
196
197    def teardown_test(self):
198        self.cleanup_tests()
199
200    def teardown_class(self):
201        if self.router_adv_daemon:
202            self.router_adv_daemon.stop()
203        try:
204            output_path = context.get_current_context().get_base_output_path()
205            test_class_name = context.get_current_context().test_class_name
206
207            output_file(f'{output_path}/{test_class_name}/rvr_summary.html',
208                        title='RvR Sumamry')
209            save(list(self.rvr_graph_summary))
210        except Exception as e:
211            self.log.error(f'Unable to generate RvR summary file: {e}')
212
213        super().teardown_class()
214
215    def on_fail(self, test_name, begin_time):
216        super().on_fail(test_name, begin_time)
217        self.cleanup_tests()
218
219    def cleanup_tests(self):
220        """Cleans up all the dangling pieces of the tests, for example, the
221        iperf server, radvd, all the currently running APs, and the various
222        clients running during the tests.
223        """
224
225        if self.router_adv_daemon:
226            output_path = context.get_current_context().get_base_output_path()
227            full_output_path = os.path.join(output_path, "radvd_log.txt")
228            radvd_log_file = open(full_output_path, 'w')
229            radvd_log_file.write(self.router_adv_daemon.pull_logs())
230            radvd_log_file.close()
231            self.router_adv_daemon.stop()
232        if hasattr(self, "android_devices"):
233            for ad in self.android_devices:
234                ad.droid.wakeLockRelease()
235                ad.droid.goToSleepNow()
236        if self.iperf_server:
237            self.iperf_server.stop()
238        self.dut.turn_location_off_and_scan_toggle_off()
239        self.dut.disconnect()
240        self.dut.reset_wifi()
241        self.download_ap_logs()
242        self.access_point.stop_all_aps()
243
244    def _wait_for_ipv4_addrs(self):
245        """Wait for an IPv4 addresses to become available on the DUT and iperf
246        server.
247
248        Returns:
249           A string containing the private IPv4 address of the iperf server.
250
251        Raises:
252            TestFailure: If unable to acquire a IPv4 address.
253        """
254        ip_address_checker_counter = 0
255        ip_address_checker_max_attempts = 3
256        while ip_address_checker_counter < ip_address_checker_max_attempts:
257            self.iperf_server.renew_test_interface_ip_address()
258            iperf_server_ip_addresses = (
259                self.iperf_server.get_interface_ip_addresses(
260                    self.iperf_server.test_interface))
261            dut_ip_addresses = self.dut.device.get_interface_ip_addresses(
262                self.dut_iperf_client.test_interface)
263
264            self.log.info(
265                'IPerf server IP info: {}'.format(iperf_server_ip_addresses))
266            self.log.info('DUT IP info: {}'.format(dut_ip_addresses))
267
268            if not iperf_server_ip_addresses['ipv4_private']:
269                self.log.warn('Unable to get the iperf server IPv4 '
270                              'address. Retrying...')
271                ip_address_checker_counter += 1
272                time.sleep(1)
273                continue
274
275            if dut_ip_addresses['ipv4_private']:
276                return iperf_server_ip_addresses['ipv4_private'][0]
277
278            self.log.warn('Unable to get the DUT IPv4 address starting at '
279                          'attenuation "{}". Retrying...'.format(
280                              self.starting_attn))
281            ip_address_checker_counter += 1
282            time.sleep(1)
283
284        asserts.fail(
285            'IPv4 addresses are not available on both the DUT and iperf server.'
286        )
287
288    # TODO (b/258264565): Merge with fuchsia_device wait_for_ipv6_addr.
289    def _wait_for_dad(self, device, test_interface):
290        """Wait for Duplicate Address Detection to resolve so that an
291        private-local IPv6 address is available for test.
292
293        Args:
294            device: implementor of get_interface_ip_addresses
295            test_interface: name of interface that DAD is operating on
296
297        Returns:
298            A string containing the private-local IPv6 address of the device.
299
300        Raises:
301            TestFailure: If unable to acquire an IPv6 address.
302        """
303        now = time.time()
304        start = now
305        elapsed = now - start
306
307        while elapsed < DAD_TIMEOUT_SEC:
308            addrs = device.get_interface_ip_addresses(test_interface)
309            now = time.time()
310            elapsed = now - start
311            if addrs['ipv6_private_local']:
312                # DAD has completed
313                addr = addrs['ipv6_private_local'][0]
314                self.log.info('DAD resolved with "{}" after {}s'.format(
315                    addr, elapsed))
316                return addr
317            time.sleep(1)
318        else:
319            asserts.fail(
320                'Unable to acquire a private-local IPv6 address for testing '
321                'after {}s'.format(elapsed))
322
323    def run_rvr(self,
324                ssid,
325                security_mode=None,
326                password=None,
327                band='2g',
328                traffic_dir='tx',
329                ip_version=4):
330        """Setups and runs the RvR test
331
332        Args:
333            ssid: The SSID for the client to associate to.
334            password: Password for the network, if necessary.
335            band: 2g or 5g
336            traffic_dir: rx or tx, bi is not supported by iperf3
337            ip_version: 4 or 6
338
339        Returns:
340            The bokeh graph data.
341        """
342        throughput = []
343        relative_attn = []
344        if band == '2g':
345            rvr_attenuators = self.attenuators_2g
346        elif band == '5g':
347            rvr_attenuators = self.attenuators_5g
348        else:
349            raise ValueError('Invalid WLAN band specified: %s' % band)
350        if ip_version == 6:
351            self.router_adv_daemon = Radvd(
352                self.access_point.ssh,
353                self.access_point.interfaces.get_bridge_interface()[0])
354            radvd_config = RadvdConfig()
355            self.router_adv_daemon.start(radvd_config)
356
357        for _ in range(0, self.debug_loop_count):
358            for rvr_attenuator in rvr_attenuators:
359                rvr_attenuator.set_atten(self.starting_attn)
360
361            associate_counter = 0
362            associate_max_attempts = 3
363            while associate_counter < associate_max_attempts:
364                if self.dut.associate(
365                        ssid,
366                        target_pwd=password,
367                        target_security=hostapd_constants.
368                        SECURITY_STRING_TO_DEFAULT_TARGET_SECURITY.get(
369                            security_mode),
370                        check_connectivity=False):
371                    break
372                else:
373                    associate_counter += 1
374            else:
375                asserts.fail('Unable to associate at starting '
376                             'attenuation: %s' % self.starting_attn)
377
378            if ip_version == 4:
379                iperf_server_ip_address = self._wait_for_ipv4_addrs()
380            elif ip_version == 6:
381                self.iperf_server.renew_test_interface_ip_address()
382                self.log.info('Waiting for iperf server to complete Duplicate '
383                              'Address Detection...')
384                iperf_server_ip_address = self._wait_for_dad(
385                    self.iperf_server, self.iperf_server.test_interface)
386
387                self.log.info('Waiting for DUT to complete Duplicate Address '
388                              'Detection for "{}"...'.format(
389                                  self.dut_iperf_client.test_interface))
390                _ = self._wait_for_dad(self.dut.device,
391                                       self.dut_iperf_client.test_interface)
392            else:
393                raise ValueError('Invalid IP version: {}'.format(ip_version))
394
395            throughput, relative_attn = (self.rvr_loop(
396                traffic_dir,
397                rvr_attenuators,
398                iperf_server_ip_address,
399                ip_version,
400                throughput=throughput,
401                relative_attn=relative_attn))
402            if self.reverse_rvr_after_forward:
403                throughput, relative_attn = self.rvr_loop(
404                    traffic_dir,
405                    rvr_attenuators,
406                    iperf_server_ip_address,
407                    ip_version,
408                    ssid=ssid,
409                    security_mode=security_mode,
410                    password=password,
411                    reverse=True,
412                    throughput=throughput,
413                    relative_attn=relative_attn)
414            self.dut.disconnect()
415
416        throughput_vs_attn = {
417            'throughput': throughput,
418            'relative_attn': relative_attn,
419            'x_label': 'Attenuation(db)',
420            'y_label': 'Throughput(%s)' % REPORTING_SPEED_UNITS
421        }
422        graph_data = {'throughput_vs_attn': throughput_vs_attn}
423        return graph_data
424
425    def rvr_loop(self,
426                 traffic_dir,
427                 rvr_attenuators,
428                 iperf_server_ip_address,
429                 ip_version,
430                 ssid=None,
431                 security_mode=None,
432                 password=None,
433                 reverse=False,
434                 throughput=None,
435                 relative_attn=None):
436        """The loop that goes through each attenuation level and runs the iperf
437        throughput pair.
438        Args:
439            traffic_dir: The traffic direction from the perspective of the DUT.
440            rvr_attenuators: A list of attenuators to set.
441            iperf_server_ip_address: The IP address of the iperf server.
442            ssid: The ssid of the wireless network that the should associated
443                to.
444            password: Password of the wireless network.
445            reverse: Whether to run RvR test starting from the highest
446                attenuation and going to the lowest.  This is run after the
447                normal low attenuation to high attenuation RvR test.
448            throughput: The list of throughput data for the test.
449            relative_attn: The list of attenuation data for the test.
450
451        Returns:
452            throughput: The list of throughput data for the test.
453            relative_attn: The list of attenuation data for the test.
454            """
455        iperf_flags = self.iperf_flags
456        if traffic_dir == 'rx':
457            iperf_flags = '%s -R' % self.iperf_flags
458        starting_attn = self.starting_attn
459        ending_attn = self.ending_attn
460        step_size_in_db = self.step_size_in_db
461        if reverse:
462            starting_attn = self.ending_attn
463            ending_attn = self.starting_attn
464            step_size_in_db = step_size_in_db * -1
465            self.dut.disconnect()
466        for step in range(starting_attn, ending_attn, step_size_in_db):
467            try:
468                for attenuator in rvr_attenuators:
469                    attenuator.set_atten(step)
470            except ValueError as e:
471                self.log.error(
472                    f'{step} is beyond the max or min of the testbed '
473                    f'attenuator\'s capability. Stopping. {e}')
474                break
475            self.log.info('Set relative attenuation to %s db' % step)
476
477            associated = self.dut.is_connected()
478            if associated:
479                self.log.info('DUT is currently associated.')
480            else:
481                self.log.info('DUT is not currently associated.')
482
483            if reverse:
484                if not associated:
485                    self.log.info('Trying to associate at relative '
486                                  'attenuation of %s db' % step)
487                    if self.dut.associate(
488                            ssid,
489                            target_pwd=password,
490                            target_security=hostapd_constants.
491                            SECURITY_STRING_TO_DEFAULT_TARGET_SECURITY.get(
492                                security_mode),
493                            check_connectivity=False):
494                        associated = True
495                        self.log.info('Successfully associated.')
496                    else:
497                        associated = False
498                        self.log.info(
499                            'Association failed. Marking a 0 %s for'
500                            ' throughput. Skipping running traffic.' %
501                            REPORTING_SPEED_UNITS)
502            attn_value_inserted = False
503            value_to_insert = str(step)
504            while not attn_value_inserted:
505                if value_to_insert in relative_attn:
506                    value_to_insert = '%s ' % value_to_insert
507                else:
508                    relative_attn.append(value_to_insert)
509                    attn_value_inserted = True
510
511            dut_ip_addresses = self.dut.device.get_interface_ip_addresses(
512                self.dut_iperf_client.test_interface)
513            if ip_version == 4:
514                if not dut_ip_addresses['ipv4_private']:
515                    self.log.info('DUT does not have an IPv4 address. '
516                                  'Traffic attempt to be run if the server '
517                                  'is pingable.')
518                else:
519                    self.log.info('DUT has the following IPv4 address: "%s"' %
520                                  dut_ip_addresses['ipv4_private'][0])
521            elif ip_version == 6:
522                if not dut_ip_addresses['ipv6_private_local']:
523                    self.log.info('DUT does not have an IPv6 address. '
524                                  'Traffic attempt to be run if the server '
525                                  'is pingable.')
526                else:
527                    self.log.info('DUT has the following IPv6 address: "%s"' %
528                                  dut_ip_addresses['ipv6_private_local'][0])
529            server_pingable = self.dut.can_ping(iperf_server_ip_address)
530            if not server_pingable:
531                self.log.info('Iperf server "%s" is not pingable. Marking '
532                              'a 0 %s for throughput. Skipping running '
533                              'traffic.' %
534                              (iperf_server_ip_address, REPORTING_SPEED_UNITS))
535            else:
536                self.log.info('Iperf server "%s" is pingable.' %
537                              iperf_server_ip_address)
538            if self.debug_pre_traffic_cmd:
539                self.log.info('\nDEBUG: Sending command \'%s\' to DUT' %
540                              self.debug_pre_traffic_cmd)
541                self.log.info(
542                    '\n%s' % self.dut.send_command(self.debug_pre_traffic_cmd))
543            if server_pingable:
544                if traffic_dir == 'tx':
545                    self.log.info('Running traffic DUT to %s at relative '
546                                  'attenuation of %s' %
547                                  (iperf_server_ip_address, step))
548                elif traffic_dir == 'rx':
549                    self.log.info('Running traffic %s to DUT at relative '
550                                  'attenuation of %s' %
551                                  (iperf_server_ip_address, step))
552                else:
553                    raise ValueError('Invalid traffic direction')
554                try:
555                    iperf_tag = 'decreasing'
556                    if reverse:
557                        iperf_tag = 'increasing'
558                    iperf_results_file = self.dut_iperf_client.start(
559                        iperf_server_ip_address,
560                        iperf_flags,
561                        '%s_%s_%s' %
562                        (iperf_tag, traffic_dir, self.starting_attn),
563                        timeout=(self.dwell_time_in_secs * 2))
564                except TimeoutError as e:
565                    iperf_results_file = None
566                    self.log.error(
567                        f'Iperf traffic timed out. Marking 0 {REPORTING_SPEED_UNITS} for '
568                        f'throughput. {e}')
569
570                if not iperf_results_file:
571                    throughput.append(0)
572                else:
573                    try:
574                        iperf_results = IPerfResult(
575                            iperf_results_file,
576                            reporting_speed_units=REPORTING_SPEED_UNITS)
577                        if iperf_results.error:
578                            self.iperf_server.stop()
579                            self.iperf_server.start()
580                            self.log.error(
581                                f'Errors in iperf logs:\n{iperf_results.error}'
582                            )
583                        if not iperf_results.avg_send_rate:
584                            throughput.append(0)
585                        else:
586                            throughput.append(iperf_results.avg_send_rate)
587                    except ValueError as e:
588                        self.iperf_server.stop()
589                        self.iperf_server.start()
590                        self.log.error(
591                            f'No data in iPerf3 file. Marking 0 {REPORTING_SPEED_UNITS} '
592                            f'for throughput: {e}')
593                        throughput.append(0)
594                    except Exception as e:
595                        self.iperf_server.stop()
596                        self.iperf_server.start()
597                        self.log.error(
598                            f'Unknown exception. Marking 0 {REPORTING_SPEED_UNITS} for '
599                            f'throughput: {e}')
600                        self.log.error(e)
601                        throughput.append(0)
602
603                self.log.info(
604                    'Iperf traffic complete. %s traffic received at '
605                    '%s %s at relative attenuation of %s db' %
606                    (traffic_dir, throughput[-1], REPORTING_SPEED_UNITS,
607                     str(relative_attn[-1]).strip()))
608
609            else:
610                self.log.debug('DUT Associated: %s' % associated)
611                self.log.debug('%s pingable: %s' %
612                               (iperf_server_ip_address, server_pingable))
613                throughput.append(0)
614            if self.debug_post_traffic_cmd:
615                self.log.info('\nDEBUG: Sending command \'%s\' to DUT' %
616                              self.debug_post_traffic_cmd)
617                self.log.info(
618                    '\n%s' %
619                    self.dut.send_command(self.debug_post_traffic_cmd))
620        return throughput, relative_attn
621
622    def test_rvr_11ac_5g_80mhz_open_tx_ipv4(self):
623        ssid = rand_ascii_str(20)
624        setup_ap(access_point=self.access_point,
625                 profile_name='whirlwind',
626                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
627                 ssid=ssid,
628                 setup_bridge=True)
629        graph_data = self.run_rvr(ssid,
630                                  band='5g',
631                                  traffic_dir='tx',
632                                  ip_version=4)
633        for rvr_graph in create_rvr_graph(
634                self.test_name,
635                context.get_current_context().get_full_output_path(),
636                graph_data):
637            self.rvr_graph_summary.append(rvr_graph)
638        write_csv_rvr_data(
639            self.test_name,
640            context.get_current_context().get_full_output_path(), graph_data)
641
642    def test_rvr_11ac_5g_80mhz_open_rx_ipv4(self):
643        ssid = rand_ascii_str(20)
644        setup_ap(access_point=self.access_point,
645                 profile_name='whirlwind',
646                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
647                 ssid=ssid,
648                 setup_bridge=True)
649        graph_data = self.run_rvr(ssid,
650                                  band='5g',
651                                  traffic_dir='rx',
652                                  ip_version=4)
653        for rvr_graph in create_rvr_graph(
654                self.test_name,
655                context.get_current_context().get_full_output_path(),
656                graph_data):
657            self.rvr_graph_summary.append(rvr_graph)
658        write_csv_rvr_data(
659            self.test_name,
660            context.get_current_context().get_full_output_path(), graph_data)
661
662    def test_rvr_11ac_5g_80mhz_open_tx_ipv6(self):
663        ssid = rand_ascii_str(20)
664        setup_ap(access_point=self.access_point,
665                 profile_name='whirlwind',
666                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
667                 ssid=ssid,
668                 setup_bridge=True)
669        graph_data = self.run_rvr(ssid,
670                                  band='5g',
671                                  traffic_dir='tx',
672                                  ip_version=6)
673        for rvr_graph in create_rvr_graph(
674                self.test_name,
675                context.get_current_context().get_full_output_path(),
676                graph_data):
677            self.rvr_graph_summary.append(rvr_graph)
678        write_csv_rvr_data(
679            self.test_name,
680            context.get_current_context().get_full_output_path(), graph_data)
681
682    def test_rvr_11ac_5g_80mhz_open_rx_ipv6(self):
683        ssid = rand_ascii_str(20)
684        setup_ap(access_point=self.access_point,
685                 profile_name='whirlwind',
686                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
687                 ssid=ssid,
688                 setup_bridge=True)
689        graph_data = self.run_rvr(ssid,
690                                  band='5g',
691                                  traffic_dir='rx',
692                                  ip_version=6)
693        for rvr_graph in create_rvr_graph(
694                self.test_name,
695                context.get_current_context().get_full_output_path(),
696                graph_data):
697            self.rvr_graph_summary.append(rvr_graph)
698        write_csv_rvr_data(
699            self.test_name,
700            context.get_current_context().get_full_output_path(), graph_data)
701
702    def test_rvr_11ac_5g_80mhz_wpa2_tx_ipv4(self):
703        ssid = rand_ascii_str(20)
704        password = rand_ascii_str(20)
705        security_profile = Security(security_mode='wpa2', password=password)
706        setup_ap(access_point=self.access_point,
707                 profile_name='whirlwind',
708                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
709                 ssid=ssid,
710                 security=security_profile,
711                 setup_bridge=True)
712        graph_data = self.run_rvr(ssid,
713                                  security_mode='wpa2',
714                                  password=password,
715                                  band='5g',
716                                  traffic_dir='tx',
717                                  ip_version=4)
718        for rvr_graph in create_rvr_graph(
719                self.test_name,
720                context.get_current_context().get_full_output_path(),
721                graph_data):
722            self.rvr_graph_summary.append(rvr_graph)
723        write_csv_rvr_data(
724            self.test_name,
725            context.get_current_context().get_full_output_path(), graph_data)
726
727    def test_rvr_11ac_5g_80mhz_wpa2_rx_ipv4(self):
728        ssid = rand_ascii_str(20)
729        password = rand_ascii_str(20)
730        security_profile = Security(security_mode='wpa2', password=password)
731        setup_ap(access_point=self.access_point,
732                 profile_name='whirlwind',
733                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
734                 ssid=ssid,
735                 security=security_profile,
736                 setup_bridge=True)
737        graph_data = self.run_rvr(ssid,
738                                  security_mode='wpa2',
739                                  password=password,
740                                  band='5g',
741                                  traffic_dir='rx',
742                                  ip_version=4)
743        for rvr_graph in create_rvr_graph(
744                self.test_name,
745                context.get_current_context().get_full_output_path(),
746                graph_data):
747            self.rvr_graph_summary.append(rvr_graph)
748        write_csv_rvr_data(
749            self.test_name,
750            context.get_current_context().get_full_output_path(), graph_data)
751
752    def test_rvr_11ac_5g_80mhz_wpa2_tx_ipv6(self):
753        ssid = rand_ascii_str(20)
754        password = rand_ascii_str(20)
755        security_profile = Security(security_mode='wpa2', password=password)
756        setup_ap(access_point=self.access_point,
757                 profile_name='whirlwind',
758                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
759                 ssid=ssid,
760                 security=security_profile,
761                 setup_bridge=True)
762        graph_data = self.run_rvr(ssid,
763                                  security_mode='wpa2',
764                                  password=password,
765                                  band='5g',
766                                  traffic_dir='tx',
767                                  ip_version=6)
768        for rvr_graph in create_rvr_graph(
769                self.test_name,
770                context.get_current_context().get_full_output_path(),
771                graph_data):
772            self.rvr_graph_summary.append(rvr_graph)
773        write_csv_rvr_data(
774            self.test_name,
775            context.get_current_context().get_full_output_path(), graph_data)
776
777    def test_rvr_11ac_5g_80mhz_wpa2_rx_ipv6(self):
778        ssid = rand_ascii_str(20)
779        password = rand_ascii_str(20)
780        security_profile = Security(security_mode='wpa2', password=password)
781        setup_ap(access_point=self.access_point,
782                 profile_name='whirlwind',
783                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
784                 ssid=ssid,
785                 security=security_profile,
786                 setup_bridge=True)
787        graph_data = self.run_rvr(ssid,
788                                  security_mode='wpa2',
789                                  password=password,
790                                  band='5g',
791                                  traffic_dir='rx',
792                                  ip_version=6)
793        for rvr_graph in create_rvr_graph(
794                self.test_name,
795                context.get_current_context().get_full_output_path(),
796                graph_data):
797            self.rvr_graph_summary.append(rvr_graph)
798        write_csv_rvr_data(
799            self.test_name,
800            context.get_current_context().get_full_output_path(), graph_data)
801
802    def test_rvr_11n_2g_20mhz_open_tx_ipv4(self):
803        ssid = rand_ascii_str(20)
804        setup_ap(access_point=self.access_point,
805                 profile_name='whirlwind',
806                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
807                 ssid=ssid,
808                 setup_bridge=True)
809        graph_data = self.run_rvr(ssid,
810                                  band='2g',
811                                  traffic_dir='tx',
812                                  ip_version=4)
813        for rvr_graph in create_rvr_graph(
814                self.test_name,
815                context.get_current_context().get_full_output_path(),
816                graph_data):
817            self.rvr_graph_summary.append(rvr_graph)
818        write_csv_rvr_data(
819            self.test_name,
820            context.get_current_context().get_full_output_path(), graph_data)
821
822    def test_rvr_11n_2g_20mhz_open_rx_ipv4(self):
823        ssid = rand_ascii_str(20)
824        setup_ap(access_point=self.access_point,
825                 profile_name='whirlwind',
826                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
827                 ssid=ssid,
828                 setup_bridge=True)
829        graph_data = self.run_rvr(ssid,
830                                  band='2g',
831                                  traffic_dir='rx',
832                                  ip_version=4)
833        for rvr_graph in create_rvr_graph(
834                self.test_name,
835                context.get_current_context().get_full_output_path(),
836                graph_data):
837            self.rvr_graph_summary.append(rvr_graph)
838        write_csv_rvr_data(
839            self.test_name,
840            context.get_current_context().get_full_output_path(), graph_data)
841
842    def test_rvr_11n_2g_20mhz_open_tx_ipv6(self):
843        ssid = rand_ascii_str(20)
844        setup_ap(access_point=self.access_point,
845                 profile_name='whirlwind',
846                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
847                 ssid=ssid,
848                 setup_bridge=True)
849        graph_data = self.run_rvr(ssid,
850                                  band='2g',
851                                  traffic_dir='tx',
852                                  ip_version=6)
853        for rvr_graph in create_rvr_graph(
854                self.test_name,
855                context.get_current_context().get_full_output_path(),
856                graph_data):
857            self.rvr_graph_summary.append(rvr_graph)
858        write_csv_rvr_data(
859            self.test_name,
860            context.get_current_context().get_full_output_path(), graph_data)
861
862    def test_rvr_11n_2g_20mhz_open_rx_ipv6(self):
863        ssid = rand_ascii_str(20)
864        setup_ap(access_point=self.access_point,
865                 profile_name='whirlwind',
866                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
867                 ssid=ssid,
868                 setup_bridge=True)
869        graph_data = self.run_rvr(ssid,
870                                  band='2g',
871                                  traffic_dir='rx',
872                                  ip_version=6)
873        for rvr_graph in create_rvr_graph(
874                self.test_name,
875                context.get_current_context().get_full_output_path(),
876                graph_data):
877            self.rvr_graph_summary.append(rvr_graph)
878        write_csv_rvr_data(
879            self.test_name,
880            context.get_current_context().get_full_output_path(), graph_data)
881
882    def test_rvr_11n_2g_20mhz_wpa2_tx_ipv4(self):
883        ssid = rand_ascii_str(20)
884        password = rand_ascii_str(20)
885        security_profile = Security(security_mode='wpa2', password=password)
886        setup_ap(access_point=self.access_point,
887                 profile_name='whirlwind',
888                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
889                 ssid=ssid,
890                 security=security_profile,
891                 setup_bridge=True)
892        graph_data = self.run_rvr(ssid,
893                                  security_mode='wpa2',
894                                  password=password,
895                                  band='2g',
896                                  traffic_dir='tx',
897                                  ip_version=4)
898        for rvr_graph in create_rvr_graph(
899                self.test_name,
900                context.get_current_context().get_full_output_path(),
901                graph_data):
902            self.rvr_graph_summary.append(rvr_graph)
903        write_csv_rvr_data(
904            self.test_name,
905            context.get_current_context().get_full_output_path(), graph_data)
906
907    def test_rvr_11n_2g_20mhz_wpa2_rx_ipv4(self):
908        ssid = rand_ascii_str(20)
909        password = rand_ascii_str(20)
910        security_profile = Security(security_mode='wpa2', password=password)
911        setup_ap(access_point=self.access_point,
912                 profile_name='whirlwind',
913                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
914                 ssid=ssid,
915                 security=security_profile,
916                 setup_bridge=True)
917        graph_data = self.run_rvr(ssid,
918                                  security_mode='wpa2',
919                                  password=password,
920                                  band='2g',
921                                  traffic_dir='rx',
922                                  ip_version=4)
923        for rvr_graph in create_rvr_graph(
924                self.test_name,
925                context.get_current_context().get_full_output_path(),
926                graph_data):
927            self.rvr_graph_summary.append(rvr_graph)
928        write_csv_rvr_data(
929            self.test_name,
930            context.get_current_context().get_full_output_path(), graph_data)
931
932    def test_rvr_11n_2g_20mhz_wpa2_tx_ipv6(self):
933        ssid = rand_ascii_str(20)
934        password = rand_ascii_str(20)
935        security_profile = Security(security_mode='wpa2', password=password)
936        setup_ap(access_point=self.access_point,
937                 profile_name='whirlwind',
938                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
939                 ssid=ssid,
940                 security=security_profile,
941                 setup_bridge=True)
942        graph_data = self.run_rvr(ssid,
943                                  security_mode='wpa2',
944                                  password=password,
945                                  band='2g',
946                                  traffic_dir='tx',
947                                  ip_version=6)
948        for rvr_graph in create_rvr_graph(
949                self.test_name,
950                context.get_current_context().get_full_output_path(),
951                graph_data):
952            self.rvr_graph_summary.append(rvr_graph)
953        write_csv_rvr_data(
954            self.test_name,
955            context.get_current_context().get_full_output_path(), graph_data)
956
957    def test_rvr_11n_2g_20mhz_wpa2_rx_ipv6(self):
958        ssid = rand_ascii_str(20)
959        password = rand_ascii_str(20)
960        security_profile = Security(security_mode='wpa2', password=password)
961        setup_ap(access_point=self.access_point,
962                 profile_name='whirlwind',
963                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
964                 ssid=ssid,
965                 security=security_profile,
966                 setup_bridge=True)
967        graph_data = self.run_rvr(ssid,
968                                  security_mode='wpa2',
969                                  password=password,
970                                  band='2g',
971                                  traffic_dir='rx',
972                                  ip_version=6)
973        for rvr_graph in create_rvr_graph(
974                self.test_name,
975                context.get_current_context().get_full_output_path(),
976                graph_data):
977            self.rvr_graph_summary.append(rvr_graph)
978        write_csv_rvr_data(
979            self.test_name,
980            context.get_current_context().get_full_output_path(), graph_data)
981