ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/config.py b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/config.py
new file mode 100644
index 0000000..1ac362e
--- /dev/null
+++ b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/config.py
@@ -0,0 +1,87 @@
+# Environment configuration
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+#
+# Currently static definition, in the future this could be a config file,
+# or even common database with host management.
+#
+
+import logging
+logger = logging.getLogger()
+
+#
+# You can put your settings in cfg.py file with setup_params, devices
+# definitions in the format as below. In other case HWSIM cfg will be used.
+#
+setup_params = {"setup_hw" : "./tests/setup_hw.sh",
+                "hostapd" : "./tests/hostapd-rt",
+                "wpa_supplicant" : "./tests/wpa_supplicant-rt",
+                "iperf" : "iperf",
+                "wlantest" : "./tests/wlantest",
+                "wlantest_cli" : "./tests/wlantest_cli",
+                "country" : "US",
+                "log_dir" : "/tmp/",
+                "ipv4_test_net" : "192.168.12.0",
+                "trace_start" : "./tests/trace_start.sh",
+                "trace_stop" : "./tests/trace_stop.sh",
+                "perf_start" : "./tests/perf_start.sh",
+                "perf_stop" : "./tests/perf_stop.sh"}
+
+#
+#devices = [{"hostname": "192.168.254.58", "ifname" : "wlan0", "port": "9877", "name" : "t2-ath9k", "flags" : "AP_HT40 STA_HT40"},
+#           {"hostname": "192.168.254.58", "ifname" : "wlan1", "port": "9877", "name" : "t2-ath10k", "flags" : "AP_VHT80"},
+#           {"hostname": "192.168.254.58", "ifname" : "wlan3", "port": "9877", "name" : "t2-intel7260", "flags" : "STA_VHT80"},
+#           {"hostname": "192.168.254.55", "ifname" : "wlan0, wlan1, wlan2", "port": "", "name" : "t3-monitor"},
+#           {"hostname": "192.168.254.50", "ifname" : "wlan0", "port": "9877", "name" : "t1-ath9k"},
+#           {"hostname": "192.168.254.50", "ifname" : "wlan1", "port": "9877", "name" : "t1-ath10k"}]
+
+#
+# HWSIM - ifaces available after modprobe mac80211_hwsim
+#
+devices = [{"hostname": "localhost", "ifname": "wlan0", "port": "9868", "name": "hwsim0", "flags": "AP_VHT80 STA_VHT80"},
+           {"hostname": "localhost", "ifname": "wlan1", "port": "9878", "name": "hwsim1", "flags": "AP_VHT80 STA_VHT80"},
+           {"hostname": "localhost", "ifname": "wlan2", "port": "9888", "name": "hwsim2", "flags": "AP_VHT80 STA_VHT80"},
+           {"hostname": "localhost", "ifname": "wlan3", "port": "9898", "name": "hwsim3", "flags": "AP_VHT80 STA_VHT80"},
+           {"hostname": "localhost", "ifname": "wlan4", "port": "9908", "name": "hwsim4", "flags": "AP_VHT80 STA_VHT80"}]
+
+
+def get_setup_params(filename="cfg.py"):
+    try:
+       mod = __import__(filename.split(".")[0])
+       return mod.setup_params
+    except:
+       logger.debug("__import__(" + filename + ") failed, using static settings")
+       pass
+    return setup_params
+
+def get_devices(filename="cfg.py"):
+    try:
+       mod = __import__(filename.split(".")[0])
+       return mod.devices
+    except:
+       logger.debug("__import__(" + filename + ") failed, using static settings")
+       pass
+    return devices
+
+def get_device(devices, name=None, flags=None, lock=False):
+    if name is None and flags is None:
+        raise Exception("Failed to get device")
+    word = name.split(":")
+    name = word[0]
+    for device in devices:
+        if device['name'] == name:
+            return device
+    for device in devices:
+        try:
+            device_flags = device['flags']
+            if device_flags.find(flags) != -1:
+                return device
+        except:
+            pass
+    raise Exception("Failed to get device " + name)
+
+def put_device(devices, name):
+    pass
diff --git a/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/hwsim_wrapper.py b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/hwsim_wrapper.py
new file mode 100644
index 0000000..38f927f
--- /dev/null
+++ b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/hwsim_wrapper.py
@@ -0,0 +1,126 @@
+# Hwsim wrapper
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import remotehost
+from wpasupplicant import WpaSupplicant
+import hostapd
+import config
+import rutils
+import monitor
+import traceback
+import wlantest
+
+import logging
+logger = logging.getLogger()
+
+def run_hwsim_test(devices, setup_params, refs, duts, monitors, hwsim_test):
+    try:
+        ref_hosts = []
+        dut_hosts = []
+        dev = []
+        apdev = []
+
+        # get hosts
+        for ref in refs:
+            ref_host = rutils.get_host(devices, ref)
+            ref_hosts.append(ref_host)
+        for dut in duts:
+            dut_host = rutils.get_host(devices, dut)
+            dut_hosts.append(dut_host)
+
+        # setup log dir
+        local_log_dir = setup_params['local_log_dir']
+
+        # setup hw before test
+        rutils.setup_hw(ref_hosts, setup_params)
+        rutils.setup_hw(dut_hosts, setup_params)
+
+        # run monitors if requested/possible
+        for ref_host in ref_hosts:
+            monitor.add(ref_host, monitors)
+            monitor.run(ref_host, setup_params)
+        for dut_host in dut_hosts:
+            monitor.add(dut_host, monitors)
+            monitor.run(dut_host, setup_params)
+
+        monitor_hosts = monitor.create(devices, setup_params, refs, duts,
+                                       monitors)
+        mon = None
+        if len(monitor_hosts) > 0:
+            mon = monitor_hosts[0]
+            wlantest.Wlantest.reset_remote_wlantest()
+            wlantest.Wlantest.register_remote_wlantest(mon, setup_params,
+                                                       monitor)
+
+        # run hostapd/wpa_supplicant
+        for ref_host in ref_hosts:
+            rutils.run_wpasupplicant(ref_host, setup_params)
+            wpas = WpaSupplicant(hostname=ref_host.host, global_iface="udp",
+                                 global_port=ref_host.port)
+            wpas.interface_add(ref_host.ifname)
+            dev.append(wpas)
+        for dut_host in dut_hosts:
+            rutils.run_hostapd(dut_host, setup_params)
+            dut_host.dev['bssid'] = rutils.get_mac_addr(dut_host)
+            apdev.append(dut_host.dev)
+
+        if hwsim_test.__code__.co_argcount == 1:
+            hwsim_test(dev)
+        elif hwsim_test.__code__.co_argcount == 2:
+            hwsim_test(dev, apdev)
+        else:
+            params = {}
+            params['long'] = 1
+            params['logdir'] = local_log_dir
+            hwsim_test(dev, apdev, params)
+
+       # hostapd/wpa_supplicant cleanup
+        for wpas in dev:
+            wpas.interface_remove(wpas.host.ifname)
+            wpas.terminate()
+        dev = []
+
+        # remove monitors
+        for ref_host in ref_hosts:
+            monitor.remove(ref_host)
+        for dut_host in dut_hosts:
+            monitor.remove(dut_host)
+
+        for ref_host in ref_hosts:
+            rutils.kill_wpasupplicant(ref_host, setup_params)
+            ref_host.get_logs(local_log_dir)
+        for dut_host in dut_hosts:
+            rutils.kill_hostapd(dut_host, setup_params)
+            dut_host.get_logs(local_log_dir)
+        if mon is not None:
+            wlantest.Wlantest.reset_remote_wlantest()
+            mon.get_logs(local_log_dir)
+
+        return ""
+    except:
+        logger.info(traceback.format_exc())
+        for wpas in dev:
+            try:
+                wpas.interface_remove(wpas.host.ifname)
+                wpas.terminate()
+            except:
+                pass
+
+        for ref_host in ref_hosts:
+            monitor.remove(ref_host)
+        for dut_host in dut_hosts:
+            monitor.remove(dut_host)
+
+        for ref_host in ref_hosts:
+            rutils.kill_wpasupplicant(ref_host, setup_params)
+            ref_host.get_logs(local_log_dir)
+        for dut_host in dut_hosts:
+            rutils.kill_hostapd(dut_host, setup_params)
+            dut_host.get_logs(local_log_dir)
+        if mon is not None:
+            wlantest.Wlantest.reset_remote_wlantest()
+            mon.get_logs(local_log_dir)
+        raise
diff --git a/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/monitor.py b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/monitor.py
new file mode 100644
index 0000000..0f77d50
--- /dev/null
+++ b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/monitor.py
@@ -0,0 +1,193 @@
+# Monitor support
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+from remotehost import Host
+import config
+import rutils
+import re
+import traceback
+import logging
+logger = logging.getLogger()
+import hostapd
+
+# standalone monitor with multi iface support
+def create(devices, setup_params, refs, duts, monitors):
+    mons = []
+    mhosts = []
+    hosts = duts + refs
+
+    # choose only standalone monitors
+    for monitor in monitors:
+        if monitor not in hosts and monitor != "all":
+            mons.append(monitor)
+
+    for mon in mons:
+        word = mon.split(":")
+        dev = config.get_device(devices, word[0])
+        if dev is None:
+            continue
+
+        host = Host(host=dev['hostname'],
+                    ifname=dev['ifname'],
+                    port=dev['port'],
+                    name=dev['name'])
+
+        for iface_param in word[1:]:
+            params = iface_param.split(",")
+            if len(params) > 3:
+                monitor_param = { "freq" : rutils.c2f(params[0]),
+                                  "bw" : params[1],
+                                  "center_freq1" : rutils.c2f(params[2]),
+                                  "center_freq2" : rutils.c2f(params[3]) }
+                host.monitor_params.append(monitor_param)
+
+        try:
+            host.execute(["iw", "reg", "set", setup_params['country']])
+            rutils.setup_hw_host(host, setup_params, True)
+        except:
+            pass
+        mhosts.append(host)
+
+    return mhosts
+
+def destroy(devices, hosts):
+    for host in hosts:
+        stop(host)
+        for monitor in host.monitors:
+            host.execute(["ifconfig", monitor, "down"])
+        host.monitor_params = []
+
+def setup(host, monitor_params=None):
+    if host is None:
+        return
+
+    if monitor_params == None:
+        monitor_params = host.monitor_params
+
+    ifaces = re.split('; | |, ', host.ifname)
+    count = 0
+    for param in monitor_params:
+        try:
+            iface = ifaces[count]
+        except:
+            logger.debug(traceback.format_exc())
+            break
+        host.execute(["ifconfig", iface, " down"])
+        host.execute(["rfkill", "unblock", "wifi"])
+        host.execute(["iw", iface, "set type monitor"])
+        host.execute(["ifconfig", iface, "up"])
+        status, buf = host.execute(["iw", iface, "set", "freq", param['freq'],
+                                    param['bw'], param['center_freq1'],
+                                    param['center_freq2']])
+        if status != 0:
+            logger.debug("Could not setup monitor interface: " + buf)
+            continue
+        host.monitors.append(iface)
+        count = count + 1
+
+def run(host, setup_params):
+    monitor_res = []
+    log_monitor = ""
+    if host is None:
+        return None
+    if len(host.monitors) == 0:
+        return None
+    try:
+        log_dir = setup_params['log_dir']
+        tc_name = setup_params['tc_name']
+    except:
+        return None
+
+    tshark = "tshark"
+    for monitor in host.monitors:
+        host.execute(["ifconfig", monitor, "up"])
+        tshark = tshark + " -i " + monitor
+        log_monitor = log_monitor + "_" + monitor
+
+    log = log_dir + tc_name + "_" + host.name + log_monitor + ".pcap"
+    host.add_log(log)
+    thread = host.thread_run([tshark, "-w", log], monitor_res)
+    host.thread = thread
+
+
+def stop(host):
+    if host is None:
+        return
+    if len(host.monitors) == 0:
+        return
+    if host.thread is None:
+        return
+
+    host.thread_stop(host.thread)
+    host.thread = None
+
+# Add monitor to existing interface
+def add(host, monitors):
+    if host is None:
+        return
+
+    for monitor in monitors:
+        if monitor != "all" and monitor != host.name:
+            continue
+        mon = "mon_" + host.ifname
+        status, buf = host.execute(["iw", host.ifname, "interface", "add", mon,
+                                    "type", "monitor"])
+        if status == 0:
+            host.monitors.append(mon)
+            host.execute(["ifconfig", mon, "up"])
+        else:
+            logger.debug("Could not add monitor for " + host.name)
+
+def remove(host):
+    stop(host)
+    for monitor in host.monitors:
+        host.execute(["iw", monitor, "del"])
+        host.monitors.remove(monitor)
+
+
+# get monitor params from hostapd/wpa_supplicant
+def get_monitor_params(wpa, is_p2p=False):
+    if is_p2p:
+        get_status_field_f = wpa.get_group_status_field
+    else:
+        get_status_field_f = wpa.get_status_field
+    freq = get_status_field_f("freq")
+    bw = "20"
+    center_freq1 = ""
+    center_freq2 = ""
+
+    vht_oper_chwidth = get_status_field_f("vht_oper_chwidth")
+    secondary_channel = get_status_field_f("secondary_channel")
+    vht_oper_centr_freq_seg0_idx = get_status_field_f("vht_oper_centr_freq_seg0_idx")
+    vht_oper_centr_freq_seg1_idx = get_status_field_f("vht_oper_centr_freq_seg1_idx")
+    if vht_oper_chwidth == "0" or vht_oper_chwidth is None:
+        if secondary_channel == "1":
+            bw = "40"
+            center_freq1 = str(int(freq) + 10)
+        elif secondary_channel == "-1":
+            center_freq1 = str(int(freq) - 10)
+        else:
+            pass
+    elif vht_oper_chwidth == "1":
+        bw = "80"
+        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
+    elif vht_oper_chwidth == "2":
+        bw = "160"
+        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
+    elif vht_oper_chwidth == "3":
+        bw = "80+80"
+        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
+        center_freq2 = str(int(vht_oper_centr_freq_seg1_idx) * 5 + 5000)
+    else:
+        pass
+
+    monitor_params = {"freq" : freq,
+                      "bw" : bw,
+                      "center_freq1" : center_freq1,
+                      "center_freq2" : center_freq2}
+
+    return monitor_params
diff --git a/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/run-tests.py b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/run-tests.py
new file mode 100644
index 0000000..67993a3
--- /dev/null
+++ b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/run-tests.py
@@ -0,0 +1,408 @@
+#!/usr/bin/env python3
+#
+# Remote test case executor
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import re
+import sys
+import time
+import traceback
+import getopt
+from datetime import datetime
+from random import shuffle
+
+import logging
+logger = logging.getLogger()
+
+scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
+sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
+sys.path.append(os.path.join(scriptsdir, '..', 'hwsim'))
+
+import wpaspy
+import config
+from test_devices import show_devices
+from test_devices import check_devices
+from rutils import TestSkip
+from utils import HwsimSkip
+from hwsim_wrapper import run_hwsim_test
+
+def usage():
+    print("USAGE: " + sys.argv[0] + " -t devices")
+    print("USAGE: " + sys.argv[0] + " -t check_devices")
+    print("USAGE: " + sys.argv[0] + " -d <dut_name> -t <all|sanity|tests_to_run> [-r <ref_name>] [-c <cfg_file.py>] [-m <all|monitor_name>] [-h hwsim_tests] [-f hwsim_modules][-R][-T][-P][-S][-v]")
+    print("USAGE: " + sys.argv[0])
+
+def get_devices(devices, duts, refs, monitors):
+    for dut in duts:
+        config.get_device(devices, dut, lock=True)
+    for ref in refs:
+        config.get_device(devices, ref, lock=True)
+    for monitor in monitors:
+        if monitor == "all":
+            continue
+        if monitor in duts:
+            continue
+        if monitor in refs:
+            continue
+        config.get_device(devices, monitor, lock=True)
+
+def put_devices(devices, duts, refs, monitors):
+    for dut in duts:
+        config.put_device(devices, dut)
+    for ref in refs:
+        config.put_device(devices, ref)
+    for monitor in monitors:
+        if monitor == "all":
+            continue
+        if monitor in duts:
+            continue
+        if monitor in refs:
+            continue
+        config.put_device(devices, monitor)
+
+def main():
+    duts = []
+    refs = []
+    monitors = []
+    filter_keys = []
+    requested_tests = ["help"]
+    requested_hwsim_tests = []
+    hwsim_tests = []
+    requested_modules = []
+    modules_tests = []
+    cfg_file = "cfg.py"
+    log_dir = "./logs/"
+    verbose = False
+    trace = False
+    restart = False
+    perf = False
+    shuffle_tests = False
+
+    # parse input parameters
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "d:f:r:t:l:k:c:m:h:vRPTS",
+                                   ["dut=", "modules=", "ref=", "tests=",
+                                    "log-dir=",
+                                    "cfg=", "key=", "monitor=", "hwsim="])
+    except getopt.GetoptError as err:
+        print(err)
+        usage()
+        sys.exit(2)
+
+    for option, argument in opts:
+        if option == "-v":
+            verbose = True
+        elif option == "-R":
+            restart = True
+        elif option == "-T":
+            trace = True
+        elif option == "-P":
+            perf = True
+        elif option == "-S":
+            shuffle_tests = True
+        elif option in ("-d", "--dut"):
+            duts.append(argument)
+        elif option in ("-r", "--ref"):
+            refs.append(argument)
+        elif option in ("-t", "--tests"):
+            requested_tests = re.split('; | |, ', argument)
+        elif option in ("-l", "--log-dir"):
+            log_dir = argument
+        elif option in ("-k", "--key"):
+            filter_keys.append(argument)
+        elif option in ("-m", "--monitor"):
+            monitors.append(argument)
+        elif option in ("-c", "--cfg"):
+            cfg_file = argument
+        elif option in ("-h", "--hwsim"):
+            requested_hwsim_tests = re.split('; | |, ', argument)
+        elif option in ("-f", "--modules"):
+            requested_modules = re.split('; | |, ', argument)
+        else:
+            assert False, "unhandled option"
+
+    # get env configuration
+    setup_params = config.get_setup_params(cfg_file)
+    devices = config.get_devices(cfg_file)
+
+    # put logs in log_dir
+    symlink = os.path.join(log_dir, "current");
+    if os.path.exists(symlink):
+        os.unlink(symlink)
+    log_dir = os.path.join(log_dir, time.strftime("%Y_%m_%d_%H_%M_%S"))
+    if not os.path.exists(log_dir):
+        os.makedirs(log_dir)
+    os.symlink(os.path.join("../", log_dir), symlink)
+
+    # setup restart/trace/perf request
+    setup_params['local_log_dir'] = log_dir
+    setup_params['restart_device'] = restart
+    setup_params['trace'] = trace
+    setup_params['perf'] = perf
+
+    # configure logger
+    logger.setLevel(logging.DEBUG)
+
+    stdout_handler = logging.StreamHandler()
+    stdout_handler.setLevel(logging.WARNING)
+    if verbose:
+        stdout_handler.setLevel(logging.DEBUG)
+    logger.addHandler(stdout_handler)
+
+    formatter = logging.Formatter('%(asctime)s - %(message)s')
+    file_name = os.path.join(log_dir, 'run-tests.log')
+    log_handler = logging.FileHandler(file_name)
+    log_handler.setLevel(logging.DEBUG)
+    log_handler.setFormatter(formatter)
+    logger.addHandler(log_handler)
+
+    # import available tests
+    tests = []
+    failed = []
+    test_modules = []
+    files = os.listdir(scriptsdir)
+    for t in files:
+        m = re.match(r'(test_.*)\.py$', t)
+        if m:
+            mod = __import__(m.group(1))
+            test_modules.append(mod.__name__.replace('test_', '', 1))
+            for key, val in mod.__dict__.items():
+                if key.startswith("test_"):
+                    tests.append(val)
+    test_names = list(set([t.__name__.replace('test_', '', 1) for t in tests]))
+
+    # import test_*
+    files = os.listdir("../hwsim/")
+    for t in files:
+        m = re.match(r'(test_.*)\.py$', t)
+        if m:
+            mod = __import__(m.group(1))
+            test_modules.append(mod.__name__.replace('test_', '', 1))
+            for key, val in mod.__dict__.items():
+                if key.startswith("test_"):
+                    hwsim_tests.append(val)
+
+    # setup hwsim tests
+    hwsim_tests_to_run = []
+    if len(requested_hwsim_tests) > 0:
+        # apply filters
+        for filter_key in filter_keys:
+            filtered_tests = []
+            for hwsim_test in hwsim_tests:
+                if re.search(filter_key, hwsim_test.__name__):
+                    filtered_tests.append(hwsim_test)
+            hwsim_tests = filtered_tests
+
+        # setup hwsim_test we should run
+        if requested_hwsim_tests[0] == "all":
+            hwsim_tests_to_run = hwsim_tests
+        elif requested_hwsim_tests[0] == "remote":
+            hwsim_tests_to_run = [t for t in hwsim_tests
+                                  if hasattr(t, "remote_compatible") and
+                                     t.remote_compatible]
+        else:
+            for test in requested_hwsim_tests:
+                t = None
+                for tt in hwsim_tests:
+                    name = tt.__name__.replace('test_', '', 1)
+                    if name == test:
+                        t = tt
+                        break
+                if not t:
+                    logger.warning("hwsim test case: " + test + " NOT-FOUND")
+                    continue
+                hwsim_tests_to_run.append(t)
+
+    # import test_* from modules
+    files = os.listdir("../hwsim/")
+    for t in files:
+        m = re.match(r'(test_.*)\.py$', t)
+        if m:
+            mod = __import__(m.group(1))
+            if mod.__name__.replace('test_', '', 1) not in requested_modules:
+                continue
+            for key, val in mod.__dict__.items():
+                if key.startswith("test_"):
+                    modules_tests.append(val)
+
+    if len(requested_modules) > 0:
+        requested_hwsim_tests = modules_tests
+        hwsim_tests_to_run = modules_tests
+
+    # sort the list
+    test_names.sort()
+    tests.sort(key=lambda t: t.__name__)
+
+    # print help
+    if requested_tests[0] == "help" and len(requested_hwsim_tests) == 0:
+        usage()
+        print("\nAvailable Devices:")
+        for device in devices:
+            print("\t", device['name'])
+        print("\nAvailable tests:")
+        for test in test_names:
+            print("\t", test)
+        print("\nAvailable hwsim tests:")
+        for hwsim_test in hwsim_tests:
+            print("\t", hwsim_test.__name__.replace('test_', '', 1))
+        return
+
+    # show/check devices
+    if requested_tests[0] == "devices":
+        show_devices(devices, setup_params)
+        return
+
+    # apply filters
+    for filter_key in filter_keys:
+        filtered_tests = []
+        for test in tests:
+            if re.search(filter_key, test.__name__):
+                filtered_tests.append(test)
+        tests = filtered_tests
+
+    # setup test we should run
+    tests_to_run = []
+    if requested_tests[0] == "all":
+        tests_to_run = tests
+    if requested_tests[0] == "help":
+        pass
+    elif requested_tests[0] == "sanity":
+        for test in tests:
+            if test.__name__.startswith("test_sanity_"):
+                tests_to_run.append(test)
+    else:
+        for test in requested_tests:
+            t = None
+            for tt in tests:
+                name = tt.__name__.replace('test_', '', 1)
+                if name == test:
+                    t = tt
+                    break
+            if not t:
+                logger.warning("test case: " + test + " NOT-FOUND")
+                continue
+            tests_to_run.append(t)
+
+    if shuffle_tests:
+        shuffle(tests_to_run)
+        shuffle(hwsim_tests_to_run)
+
+    # lock devices
+    try:
+        get_devices(devices, duts, refs, monitors)
+    except Exception as e:
+        logger.warning("get devices failed: " + str(e))
+        logger.info(traceback.format_exc())
+        put_devices(devices, duts, refs, monitors)
+        return
+    except:
+        logger.warning("get devices failed")
+        logger.info(traceback.format_exc())
+        put_devices(devices, duts, refs, monitors)
+        return
+
+    # now run test cases
+    for dut in duts:
+        if len(requested_hwsim_tests) > 0:
+            logger.warning("DUT (apdev): " + str(dut))
+        else:
+            logger.warning("DUT: " + str(dut))
+    for ref in refs:
+        if len(requested_hwsim_tests) > 0:
+            logger.warning("REF   (dev): " + str(ref))
+        else:
+            logger.warning("REF: " + str(ref))
+    for monitor in monitors:
+        logger.warning("MON: " + str(monitor))
+
+    # run check_devices at beginning
+    logger.warning("RUN check_devices")
+    try:
+        check_devices(devices, setup_params, refs, duts, monitors)
+    except Exception as e:
+        logger.warning("FAILED: " + str(e))
+        logger.info(traceback.format_exc())
+        put_devices(devices, duts, refs, monitors)
+        return
+    except:
+        logger.warning("FAILED")
+        logger.info(traceback.format_exc())
+        put_devices(devices, duts, refs, monitors)
+        return
+    logger.warning("PASS")
+
+    test_no = 1
+    for test in tests_to_run:
+        try:
+            start = datetime.now()
+            setup_params['tc_name'] = test.__name__.replace('test_', '', 1)
+            logger.warning("START - " + setup_params['tc_name'] + " (" + str(test_no) + "/" + str(len(tests_to_run)) + ")")
+            if test.__doc__:
+                logger.info("Test: " + test.__doc__)
+
+            # run tc
+            res = test(devices, setup_params, refs, duts, monitors)
+
+            end = datetime.now()
+            logger.warning("PASS (" + res + ") - " + str((end - start).total_seconds()) + "s")
+        except KeyboardInterrupt:
+            put_devices(devices, duts, refs, monitors)
+            raise
+        except TestSkip as e:
+            end = datetime.now()
+            logger.warning("SKIP (" + str(e) + ") - " + str((end - start).total_seconds()) + "s")
+        except Exception as e:
+            end = datetime.now()
+            logger.warning("FAILED (" + str(e) + ") - " + str((end - start).total_seconds()) + "s")
+            logger.info(traceback.format_exc())
+            failed.append(test.__name__.replace('test_', '', 1))
+        except:
+            end = datetime.now()
+            logger.warning("FAILED - " + str((end - start).total_seconds()) + "s")
+            logger.info(traceback.format_exc())
+            failed.append(test.__name__.replace('test_', '', 1))
+        test_no += 1
+
+    test_no = 1
+    for hwsim_test in hwsim_tests_to_run:
+        try:
+            start = datetime.now()
+            setup_params['tc_name'] = hwsim_test.__name__.replace('test_', '', 1)
+            logger.warning("START - " + setup_params['tc_name'] + " (" + str(test_no) + "/" + str(len(hwsim_tests_to_run)) + ")")
+            res = run_hwsim_test(devices, setup_params, refs, duts, monitors, hwsim_test)
+            end = datetime.now()
+            logger.warning("PASS (" + res + ") - " + str((end - start).total_seconds()) + "s")
+        except KeyboardInterrupt:
+            put_devices(devices, duts, refs, monitors)
+            raise
+        except HwsimSkip as e:
+            end = datetime.now()
+            logger.warning("SKIP (" + str(e) + ") - " + str((end - start).total_seconds()) + "s")
+            failed.append(hwsim_test.__name__.replace('test_', '', 1))
+        except Exception as e:
+            end = datetime.now()
+            logger.warning("FAILED (" + str(e) + ") - " + str((end - start).total_seconds()) + "s")
+            logger.info(traceback.format_exc())
+            failed.append(hwsim_test.__name__.replace('test_', '', 1))
+        except:
+            end = datetime.now()
+            logger.warning("FAILED - " + str((end - start).total_seconds()) + "s")
+            logger.info(traceback.format_exc())
+            failed.append(hwsim_test.__name__.replace('test_', '', 1))
+        test_no += 1
+
+    # unlock devices
+    put_devices(devices, duts, refs, monitors)
+
+    if len(failed) > 0:
+        logger.warning("Failed test cases:")
+        for test in failed:
+            logger.warning("\t" + test)
+
+
+if __name__ == "__main__":
+        main()
diff --git a/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/rutils.py b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/rutils.py
new file mode 100644
index 0000000..6902991
--- /dev/null
+++ b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/rutils.py
@@ -0,0 +1,567 @@
+# Utils
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import re
+import time
+from remotehost import Host
+import hostapd
+import config
+
+class TestSkip(Exception):
+    def __init__(self, reason):
+        self.reason = reason
+    def __str__(self):
+        return self.reason
+
+# get host based on name
+def get_host(devices, dev_name):
+    dev = config.get_device(devices, dev_name)
+    host = Host(host=dev['hostname'],
+                ifname=dev['ifname'],
+                port=dev['port'],
+                name=dev['name'])
+    host.dev = dev
+    return host
+
+# Run setup_hw - hardware specific
+def setup_hw_host_iface(host, iface, setup_params, force_restart=False):
+    try:
+        setup_hw = setup_params['setup_hw']
+        restart = ""
+        try:
+            if setup_params['restart_device'] == True:
+                restart = "-R"
+        except:
+            pass
+
+        if force_restart:
+            restart = "-R"
+
+        host.execute([setup_hw, "-I", iface, restart])
+    except:
+        pass
+
+def setup_hw_host(host, setup_params, force_restart=False):
+    ifaces = re.split('; | |, ', host.ifname)
+    for iface in ifaces:
+        setup_hw_host_iface(host, iface, setup_params, force_restart)
+
+def setup_hw(hosts, setup_params, force_restart=False):
+    for host in hosts:
+        setup_hw_host(host, setup_params, force_restart)
+
+# get traces - hw specific
+def trace_start(hosts, setup_params):
+    for host in hosts:
+        trace_start_stop(host, setup_params, start=True)
+
+def trace_stop(hosts, setup_params):
+    for host in hosts:
+        trace_start_stop(host, setup_params, start=False)
+
+def trace_start_stop(host, setup_params, start):
+    if setup_params['trace'] == False:
+        return
+    try:
+        start_trace = setup_params['trace_start']
+        stop_trace = setup_params['trace_stop']
+        if start:
+            cmd = start_trace
+        else:
+            cmd = stop_trace
+        trace_dir = setup_params['log_dir'] + host.ifname + "/remote_traces"
+        host.add_log(trace_dir + "/*")
+        host.execute([cmd, "-I", host.ifname, "-D", trace_dir])
+    except:
+        pass
+
+# get perf
+def perf_start(hosts, setup_params):
+    for host in hosts:
+        perf_start_stop(host, setup_params, start=True)
+
+def perf_stop(hosts, setup_params):
+    for host in hosts:
+        perf_start_stop(host, setup_params, start=False)
+
+def perf_start_stop(host, setup_params, start):
+    if setup_params['perf'] == False:
+        return
+    try:
+        perf_start = setup_params['perf_start']
+        perf_stop = setup_params['perf_stop']
+        if start:
+            cmd = perf_start
+        else:
+            cmd = perf_stop
+        perf_dir = setup_params['log_dir'] + host.ifname + "/remote_perf"
+        host.add_log(perf_dir + "/*")
+        host.execute([cmd, "-I", host.ifname, "-D", perf_dir])
+    except:
+        pass
+
+# hostapd/wpa_supplicant helpers
+def run_hostapd(host, setup_params):
+    log_file = None
+    try:
+        tc_name = setup_params['tc_name']
+        log_dir = setup_params['log_dir']
+        log_file = log_dir + tc_name + "_hostapd_" + host.name + "_" + host.ifname + ".log"
+        host.execute(["rm", log_file])
+        log = " -f " + log_file
+    except:
+        log = ""
+
+    if log_file:
+        host.add_log(log_file)
+    pidfile = setup_params['log_dir'] + "hostapd_" + host.ifname + "_" + setup_params['tc_name'] + ".pid"
+    status, buf = host.execute([setup_params['hostapd'], "-B", "-ddt", "-g", "udp:" + host.port, "-P", pidfile, log])
+    if status != 0:
+        raise Exception("Could not run hostapd: " + buf)
+
+def run_wpasupplicant(host, setup_params):
+    log_file = None
+    try:
+        tc_name = setup_params['tc_name']
+        log_dir = setup_params['log_dir']
+        log_file = log_dir + tc_name + "_wpa_supplicant_" + host.name + "_" + host.ifname + ".log"
+        host.execute(["rm", log_file])
+        log = " -f " + log_file
+    except:
+        log = ""
+
+    if log_file:
+        host.add_log(log_file)
+    pidfile = setup_params['log_dir'] + "wpa_supplicant_" + host.ifname + "_" + setup_params['tc_name'] + ".pid"
+    status, buf = host.execute([setup_params['wpa_supplicant'], "-B", "-ddt", "-g", "udp:" + host.port, "-P", pidfile, log])
+    if status != 0:
+        raise Exception("Could not run wpa_supplicant: " + buf)
+
+def kill_wpasupplicant(host, setup_params):
+    pidfile = setup_params['log_dir'] + "wpa_supplicant_" + host.ifname + "_" + setup_params['tc_name'] + ".pid"
+    host.execute(["kill `cat " + pidfile + "`"])
+
+def kill_hostapd(host, setup_params):
+    pidfile = setup_params['log_dir'] + "hostapd_" + host.ifname + "_" + setup_params['tc_name'] + ".pid"
+    host.execute(["kill `cat " + pidfile + "`"])
+
+def get_ap_params(channel="1", bw="HT20", country="US", security="open", ht_capab=None, vht_capab=None):
+    ssid = "test_" + channel + "_" + security + "_" + bw
+
+    if bw == "b_only":
+        params = hostapd.b_only_params(channel, ssid, country)
+    elif bw == "g_only":
+        params = hostapd.g_only_params(channel, ssid, country)
+    elif bw == "g_only_wmm":
+        params = hostapd.g_only_params(channel, ssid, country)
+        params['wmm_enabled'] = "1"
+    elif bw == "a_only":
+        params = hostapd.a_only_params(channel, ssid, country)
+    elif bw == "a_only_wmm":
+        params = hostapd.a_only_params(channel, ssid, country)
+        params['wmm_enabled'] = "1"
+    elif bw == "HT20":
+        params = hostapd.ht20_params(channel, ssid, country)
+        if ht_capab:
+            try:
+                params['ht_capab'] = params['ht_capab'] + ht_capab
+            except:
+                params['ht_capab'] = ht_capab
+    elif bw == "HT40+":
+        params = hostapd.ht40_plus_params(channel, ssid, country)
+        if ht_capab:
+            params['ht_capab'] = params['ht_capab'] + ht_capab
+    elif bw == "HT40-":
+        params = hostapd.ht40_minus_params(channel, ssid, country)
+        if ht_capab:
+            params['ht_capab'] = params['ht_capab'] + ht_capab
+    elif bw == "VHT80":
+        params = hostapd.ht40_plus_params(channel, ssid, country)
+        if ht_capab:
+            params['ht_capab'] = params['ht_capab'] + ht_capab
+        if vht_capab:
+            try:
+                params['vht_capab'] = params['vht_capab'] + vht_capab
+            except:
+                params['vht_capab'] = vht_capab
+        params['ieee80211ac'] = "1"
+        params['vht_oper_chwidth'] = "1"
+        params['vht_oper_centr_freq_seg0_idx'] = str(int(channel) + 6)
+    else:
+        params = {}
+
+    # now setup security params
+    if security == "tkip":
+        sec_params = hostapd.wpa_params(passphrase="testtest")
+    elif security == "ccmp":
+        sec_params = hostapd.wpa2_params(passphrase="testtest")
+    elif security == "mixed":
+        sec_params = hostapd.wpa_mixed_params(passphrase="testtest")
+    elif security == "wep":
+        sec_params = {"wep_key0" : "123456789a",
+                      "wep_default_key" : "0",
+                      "auth_algs" : "1"}
+    elif security == "wep_shared":
+        sec_params = {"wep_key0" : "123456789a",
+                      "wep_default_key" : "0",
+                      "auth_algs" : "2"}
+    else:
+        sec_params = {}
+
+    params.update(sec_params)
+
+    return params
+
+# ip helpers
+def get_ipv4(client, ifname=None):
+    if ifname is None:
+        ifname = client.ifname
+    status, buf = client.execute(["ifconfig", ifname])
+    lines = buf.splitlines()
+
+    for line in lines:
+        res = line.find("inet addr:")
+        if res != -1:
+            break
+
+    if res != -1:
+        words = line.split()
+        addr = words[1].split(":")
+        return addr[1]
+
+    return "unknown"
+
+def get_ipv6(client, ifname=None):
+    res = -1
+    if ifname is None:
+        ifname = client.ifname
+    status, buf = client.execute(["ifconfig", ifname])
+    lines = buf.splitlines()
+
+    for line in lines:
+        res = line.find("Scope:Link")
+        if res == -1:
+            res = line.find("<link>")
+        if res != -1:
+            break
+
+    if res != -1:
+        words = line.split()
+        if words[0] == "inet6" and words[1] == "addr:":
+            addr_mask = words[2]
+            addr = addr_mask.split("/")
+            return addr[0]
+        if words[0] == "inet6":
+            return words[1]
+
+    return "unknown"
+
+def get_ip(client, addr_type="ipv6", iface=None):
+    if addr_type == "ipv6":
+        return get_ipv6(client, iface)
+    elif addr_type == "ipv4":
+        return get_ipv4(client, iface)
+    else:
+        return "unknown addr_type: " + addr_type
+
+def get_ipv4_addr(setup_params, number):
+    try:
+        ipv4_base = setup_params['ipv4_test_net']
+    except:
+        ipv4_base = "172.16.12.0"
+
+    parts = ipv4_base.split('.')
+    ipv4 = parts[0] + "." + parts[1] + "." + parts[2] + "." + str(number)
+
+    return ipv4
+
+def get_mac_addr(host, iface=None):
+    if iface == None:
+        iface = host.ifname
+    status, buf = host.execute(["ifconfig", iface])
+    if status != 0:
+        raise Exception("ifconfig " + iface)
+    words = buf.split()
+    found = 0
+    for word in words:
+        if found == 1:
+            return word
+        if word == "HWaddr" or word == "ether":
+            found = 1
+    raise Exception("Could not find HWaddr")
+
+# connectivity/ping helpers
+def get_ping_packet_loss(ping_res):
+    loss_line = ""
+    lines = ping_res.splitlines()
+    for line in lines:
+        if line.find("packet loss") != -1:
+            loss_line = line
+            break;
+
+    if loss_line == "":
+        return "100%"
+
+    sections = loss_line.split(",")
+
+    for section in sections:
+        if section.find("packet loss") != -1:
+            words = section.split()
+            return words[0]
+
+    return "100%"
+
+def ac_to_ping_ac(qos):
+    if qos == "be":
+        qos_param = "0x00"
+    elif qos == "bk":
+        qos_param = "0x20"
+    elif qos == "vi":
+        qos_param = "0xA0"
+    elif qos == "vo":
+        qos_param = "0xE0"
+    else:
+        qos_param = "0x00"
+    return qos_param
+
+def ping_run(host, ip, result, ifname=None, addr_type="ipv4", deadline="5", qos=None):
+    if ifname is None:
+       ifname = host.ifname
+    if addr_type == "ipv6":
+        ping = ["ping6"]
+    else:
+        ping = ["ping"]
+
+    ping = ping + ["-w", deadline, "-I", ifname]
+    if qos:
+        ping = ping + ["-Q", ac_to_ping_ac(qos)]
+    ping = ping + [ip]
+
+    flush_arp_cache(host)
+
+    thread = host.thread_run(ping, result)
+    return thread
+
+def ping_wait(host, thread, timeout=None):
+    host.thread_wait(thread, timeout)
+    if thread.is_alive():
+        raise Exception("ping thread still alive")
+
+def flush_arp_cache(host):
+    host.execute(["ip", "-s", "-s", "neigh", "flush", "all"])
+
+def check_connectivity(a, b, addr_type="ipv4", deadline="5", qos=None):
+    addr_a = get_ip(a, addr_type)
+    addr_b = get_ip(b, addr_type)
+
+    if addr_type == "ipv4":
+        ping = ["ping"]
+    else:
+        ping = ["ping6"]
+
+    ping_a_b = ping + ["-w", deadline, "-I", a.ifname]
+    ping_b_a = ping + ["-w", deadline, "-I", b.ifname]
+    if qos:
+        ping_a_b = ping_a_b + ["-Q", ac_to_ping_ac(qos)]
+        ping_b_a = ping_b_a + ["-Q", ac_to_ping_ac(qos)]
+    ping_a_b = ping_a_b + [addr_b]
+    ping_b_a = ping_b_a + [addr_a]
+
+    # Clear arp cache
+    flush_arp_cache(a)
+    flush_arp_cache(b)
+
+    status, buf = a.execute(ping_a_b)
+    if status == 2 and ping == "ping6":
+        # tentative possible for a while, try again
+        time.sleep(3)
+        status, buf = a.execute(ping_a_b)
+    if status != 0:
+        raise Exception("ping " + a.name + "/" + a.ifname + " >> " + b.name + "/" + b.ifname)
+
+    a_b = get_ping_packet_loss(buf)
+
+    # Clear arp cache
+    flush_arp_cache(a)
+    flush_arp_cache(b)
+
+    status, buf = b.execute(ping_b_a)
+    if status != 0:
+        raise Exception("ping " + b.name + "/" + b.ifname + " >> " + a.name + "/" + a.ifname)
+
+    b_a = get_ping_packet_loss(buf)
+
+    if int(a_b[:-1]) > 40:
+        raise Exception("Too high packet lost: " + a_b)
+
+    if int(b_a[:-1]) > 40:
+        raise Exception("Too high packet lost: " + b_a)
+
+    return a_b, b_a
+
+
+# iperf helpers
+def get_iperf_speed(iperf_res, pattern="Mbits/sec"):
+    lines = iperf_res.splitlines()
+    sum_line = ""
+    last_line = ""
+    count = 0
+    res = -1
+
+    # first find last SUM line
+    for line in lines:
+        res = line.find("[SUM]")
+        if res != -1:
+            sum_line = line
+
+    # next check SUM status
+    if sum_line != "":
+        words = sum_line.split()
+        for word in words:
+            res = word.find(pattern)
+            if res != -1:
+                return words[count - 1] + " " + pattern
+            count = count + 1
+
+    # no SUM - one thread - find last line
+    for line in lines:
+        res = line.find(pattern)
+        if res != -1:
+            last_line = line
+
+    if last_line == "":
+        return "0 " + pattern
+
+    count = 0
+    words = last_line.split()
+    for word in words:
+        res = word.find(pattern)
+        if res != -1:
+            return words[count - 1] + " " + pattern
+            break;
+        count = count + 1
+    return "0 " + pattern
+
+def ac_to_iperf_ac(qos):
+    if qos == "be":
+        qos_param = "0x00"
+    elif qos == "bk":
+        qos_param = "0x20"
+    elif qos == "vi":
+        qos_param = "0xA0"
+    elif qos == "vo":
+        qos_param = "0xE0"
+    else:
+        qos_param = "0x00"
+    return qos_param
+
+def iperf_run(server, client, server_ip, client_res, server_res,
+              l4="udp", bw="30M", test_time="30", parallel="5",
+              qos="be", param=" -i 5 ", ifname=None, l3="ipv4",
+              port="5001", iperf="iperf"):
+    if ifname == None:
+        ifname = client.ifname
+
+    if iperf == "iperf":
+        iperf_server = [iperf]
+    elif iperf == "iperf3":
+        iperf_server = [iperf, "-1"]
+
+    if l3 == "ipv4":
+        iperf_client = [iperf, "-c", server_ip, "-p", port]
+        iperf_server = iperf_server + ["-p", port]
+    elif l3 == "ipv6":
+        iperf_client = [iperf, "-V", "-c", server_ip  + "%" + ifname, "-p", port]
+        iperf_server = iperf_server + ["-V", "-p", port]
+    else:
+        return -1, -1
+
+    iperf_server = iperf_server + ["-s", "-f", "m", param]
+    iperf_client = iperf_client + ["-f", "m", "-t", test_time]
+
+    if parallel != "1":
+        iperf_client = iperf_client + ["-P", parallel]
+
+    if l4 == "udp":
+        if iperf != "iperf3":
+            iperf_server = iperf_server + ["-u"]
+        iperf_client = iperf_client + ["-u", "-b", bw]
+
+    if qos:
+        iperf_client = iperf_client + ["-Q", ac_to_iperf_ac(qos)]
+
+    flush_arp_cache(server)
+    flush_arp_cache(client)
+
+    server_thread = server.thread_run(iperf_server, server_res)
+    time.sleep(1)
+    client_thread = client.thread_run(iperf_client, client_res)
+
+    return server_thread, client_thread
+
+def iperf_wait(server, client, server_thread, client_thread, timeout=None, iperf="iperf"):
+    client.thread_wait(client_thread, timeout)
+    if client_thread.is_alive():
+        raise Exception("iperf client thread still alive")
+
+    server.thread_wait(server_thread, 5)
+    if server_thread.is_alive():
+        server.execute(["killall", "-s", "INT", iperf])
+        time.sleep(1)
+
+    server.thread_wait(server_thread, 5)
+    if server_thread.is_alive():
+        raise Exception("iperf server thread still alive")
+
+    return
+
+def run_tp_test(server, client, l3="ipv4", iperf="iperf", l4="tcp", test_time="10", parallel="5",
+                qos="be", bw="30M", ifname=None, port="5001"):
+    client_res = []
+    server_res = []
+
+    server_ip = get_ip(server, l3)
+    time.sleep(1)
+    server_thread, client_thread = iperf_run(server, client, server_ip, client_res, server_res,
+                                             l3=l3, iperf=iperf, l4=l4, test_time=test_time,
+                                             parallel=parallel, qos=qos, bw=bw, ifname=ifname,
+                                             port=port)
+    iperf_wait(server, client, server_thread, client_thread, iperf=iperf, timeout=int(test_time) + 10)
+
+    if client_res[0] != 0:
+        raise Exception(iperf + " client: " + client_res[1])
+    if server_res[0] != 0:
+        raise Exception(iperf + " server: " + server_res[1])
+    if client_res[1] is None:
+        raise Exception(iperf + " client result issue")
+    if server_res[1] is None:
+        raise Exception(iperf + " server result issue")
+
+    if iperf == "iperf":
+          result = server_res[1]
+    if iperf == "iperf3":
+          result = client_res[1]
+
+    speed = get_iperf_speed(result)
+    return speed
+
+def get_iperf_bw(bw, parallel, spacial_streams=2):
+    if bw == "b_only":
+        max_tp = 11
+    elif bw == "g_only" or bw == "g_only_wmm" or bw == "a_only" or bw == "a_only_wmm":
+        max_tp = 54
+    elif bw == "HT20":
+        max_tp = 72 * spacial_streams
+    elif bw == "HT40+" or bw == "HT40-":
+        max_tp = 150 * spacial_streams
+    elif bw == "VHT80":
+        max_tp = 433 * spacial_streams
+    else:
+        max_tp = 150
+
+    max_tp = 1.2 * max_tp
+
+    return str(int(max_tp/int(parallel))) + "M"
diff --git a/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_devices.py b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_devices.py
new file mode 100644
index 0000000..ccd9984
--- /dev/null
+++ b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_devices.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python2
+#
+# Show/check devices
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import traceback
+import config
+import os
+import sys
+import getopt
+import re
+
+import logging
+logger = logging.getLogger()
+
+import rutils
+from remotehost import Host
+from wpasupplicant import WpaSupplicant
+import hostapd
+
+def show_devices(devices, setup_params):
+    """Show/check available devices"""
+    print("Devices:")
+    for device in devices:
+        host = rutils.get_host(devices, device['name'])
+        # simple check if authorized_keys works correctly
+        status, buf = host.execute(["id"])
+        if status != 0:
+            print("[" + host.name + "] - ssh communication:  FAILED")
+            continue
+        else:
+            print("[" + host.name + "] - ssh communication: OK")
+        # check setup_hw works correctly
+        rutils.setup_hw_host(host, setup_params)
+
+        # show uname
+        status, buf = host.execute(["uname", "-s", "-n", "-r", "-m", "-o"])
+        print("\t" + buf)
+        # show ifconfig
+        ifaces = re.split('; | |, ', host.ifname)
+        for iface in ifaces:
+            status, buf = host.execute(["ifconfig", iface])
+            if status != 0:
+                print("\t" + iface + " failed\n")
+                continue
+            lines = buf.splitlines()
+            for line in lines:
+                print("\t" + line)
+        # check hostapd, wpa_supplicant, iperf exist
+        status, buf = host.execute([setup_params['wpa_supplicant'], "-v"])
+        if status != 0:
+            print("\t" + setup_params['wpa_supplicant'] + " not find\n")
+            continue
+        lines = buf.splitlines()
+        for line in lines:
+            print("\t" + line)
+        print("")
+        status, buf = host.execute([setup_params['hostapd'], "-v"])
+        if status != 1:
+            print("\t" + setup_params['hostapd'] + " not find\n")
+            continue
+        lines = buf.splitlines()
+        for line in lines:
+            print("\t" + line)
+        print("")
+        status, buf = host.execute([setup_params['iperf'], "-v"])
+        if status != 0 and status != 1:
+            print("\t" + setup_params['iperf'] + " not find\n")
+            continue
+        lines = buf.splitlines()
+        for line in lines:
+            print("\t" + line)
+        print("")
+
+def check_device(devices, setup_params, dev_name, monitor=False):
+    host = rutils.get_host(devices, dev_name)
+    # simple check if authorized_keys works correctly
+    status, buf = host.execute(["id"])
+    if status != 0:
+        raise Exception(dev_name + " - ssh communication FAILED: " + buf)
+
+    rutils.setup_hw_host(host, setup_params)
+
+    ifaces = re.split('; | |, ', host.ifname)
+    # check interfaces (multi for monitor)
+    for iface in ifaces:
+        status, buf = host.execute(["ifconfig", iface])
+        if status != 0:
+            raise Exception(dev_name + " ifconfig " + iface + " failed: " + buf)
+
+    # monitor doesn't need wpa_supplicant/hostapd ...
+    if monitor == True:
+        return
+
+    status, buf = host.execute(["ls", "-l", setup_params['wpa_supplicant']])
+    if status != 0:
+        raise Exception(dev_name + " - wpa_supplicant: " + buf)
+
+    status, buf = host.execute(["ls", "-l", setup_params['hostapd']])
+    if status != 0:
+        raise Exception(dev_name + " - hostapd: " + buf)
+
+    status, buf = host.execute(["which", setup_params['iperf']])
+    if status != 0:
+        raise Exception(dev_name + " - iperf: " + buf)
+
+    status, buf = host.execute(["which", "tshark"])
+    if status != 0:
+        logger.debug(dev_name + " - tshark: " + buf)
+
+def check_devices(devices, setup_params, refs, duts, monitors):
+    """Check duts/refs/monitors devices"""
+    for dut in duts:
+        check_device(devices, setup_params, dut)
+    for ref in refs:
+        check_device(devices, setup_params, ref)
+    for monitor in monitors:
+        if monitor == "all":
+            continue
+        check_device(devices, setup_params, monitor, monitor=True)
diff --git a/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_example.py b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_example.py
new file mode 100644
index 0000000..1550665
--- /dev/null
+++ b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_example.py
@@ -0,0 +1,141 @@
+# Example test case
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import remotehost
+from wpasupplicant import WpaSupplicant
+import hostapd
+import config
+import rutils
+import monitor
+
+import logging
+logger = logging.getLogger()
+
+def test_example(devices, setup_params, refs, duts, monitors):
+    """TC example - simple connect and ping test"""
+    try:
+        sta = None
+        ap = None
+        hapd = None
+        wpas = None
+        mon = None
+
+        # get hosts based on name
+        sta = rutils.get_host(devices, duts[0])
+        ap = rutils.get_host(devices, refs[0])
+
+        # setup log dir
+        local_log_dir = setup_params['local_log_dir']
+
+        # setup hw before test
+        rutils.setup_hw([sta, ap], setup_params)
+
+        # run traces if requested
+        rutils.trace_start([sta], setup_params)
+
+        # run perf if requested
+        rutils.perf_start([sta], setup_params)
+
+        # run hostapd/wpa_supplicant
+        rutils.run_wpasupplicant(sta, setup_params)
+        rutils.run_hostapd(ap, setup_params)
+
+        # get ap_params
+        ap_params = rutils.get_ap_params(channel="1", bw="HT20", country="US",
+                                         security="open")
+
+        # Add monitors if requested
+        monitor_hosts = monitor.create(devices, setup_params, refs, duts,
+                                       monitors)
+        if len(monitor_hosts) > 0:
+            mon = monitor_hosts[0]
+        monitor.add(sta, monitors)
+        monitor.add(ap, monitors)
+
+        # connect to hostapd/wpa_supplicant UDP CTRL iface
+        hapd = hostapd.add_ap(ap.dev, ap_params)
+        freq = hapd.get_status_field("freq")
+        wpas = WpaSupplicant(hostname=sta.host, global_iface="udp",
+                             global_port=sta.port)
+        wpas.interface_add(sta.ifname)
+
+        # setup standalone monitor based on hapd; could be multi interface
+        # monitor
+        monitor_param = monitor.get_monitor_params(hapd)
+        monitor.setup(mon, [monitor_param])
+
+        # run monitors
+        monitor.run(sta, setup_params)
+        monitor.run(ap, setup_params)
+        monitor.run(mon, setup_params)
+
+        # connect wpa_supplicant to hostapd
+        wpas.connect(ap_params['ssid'], key_mgmt="NONE", scan_freq=freq)
+
+        # run ping test
+        ap_sta, sta_ap = rutils.check_connectivity(ap, sta, "ipv6")
+
+        # remove/destroy monitors
+        monitor.remove(sta)
+        monitor.remove(ap)
+        monitor.destroy(devices, monitor_hosts)
+
+        # hostapd/wpa_supplicant cleanup
+        wpas.interface_remove(sta.ifname)
+        wpas.terminate()
+
+        hapd.close_ctrl()
+        hostapd.remove_bss(ap.dev)
+        hostapd.terminate(ap.dev)
+
+        # stop perf
+        rutils.perf_stop([sta], setup_params)
+
+        # stop traces
+        rutils.trace_stop([sta], setup_params)
+
+        # get wpa_supplicant/hostapd/tshark logs
+        sta.get_logs(local_log_dir)
+        ap.get_logs(local_log_dir)
+        if mon:
+            mon.get_logs(local_log_dir)
+
+        return "packet_loss: " + ap_sta + ", " + sta_ap
+    except:
+        rutils.perf_stop([sta], setup_params)
+        rutils.trace_stop([sta], setup_params)
+        if wpas:
+            try:
+                wpas.interface_remove(sta.ifname)
+                wpas.terminate()
+            except:
+                pass
+        if hapd:
+            try:
+                hapd.close_ctrl()
+                hostapd.remove_bss(ap.dev)
+                hostapd.terminate(ap.dev)
+            except:
+                pass
+        if mon:
+            monitor.destroy(devices, monitor_hosts)
+            mon.get_logs(local_log_dir)
+
+        if sta:
+            monitor.remove(sta)
+            dmesg = setup_params['log_dir'] + setup_params['tc_name'] + "_" + sta.name + "_" + sta.ifname + ".dmesg"
+            sta.execute(["dmesg", "-c", ">", dmesg])
+            sta.add_log(dmesg)
+            sta.get_logs(local_log_dir)
+            sta.execute(["ifconfig", sta.ifname, "down"])
+        if ap:
+            monitor.remove(ap)
+            dmesg = setup_params['log_dir'] + setup_params['tc_name'] + "_" + ap.name + "_" + ap.ifname + ".dmesg"
+            ap.execute(["dmesg", "-c", ">", dmesg])
+            ap.add_log(dmesg)
+            ap.get_logs(local_log_dir)
+            ap.execute(["ifconfig", ap.ifname, " down"])
+        raise
diff --git a/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_monitor.py b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_monitor.py
new file mode 100644
index 0000000..c8b88d4
--- /dev/null
+++ b/package/kernel/asr-wl/asr-hostapd/asr-hostapd-2023-06-22/tests/remote/test_monitor.py
@@ -0,0 +1,52 @@
+# Monitor support
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import remotehost
+import config
+import rutils
+import monitor
+import time
+import os
+
+import logging
+logger = logging.getLogger()
+
+def run_monitor(devices, setup_params, refs, duts, monitors, seconds=None):
+    try:
+        air_monitor = []
+        output = "\n\tPCAP files:\n"
+        # setup log dir
+        local_log_dir = setup_params['local_log_dir']
+
+        # add/run monitors if requested
+        air_monitors = monitor.create(devices, setup_params, refs, duts,
+                                      monitors)
+        for air_monitor in air_monitors:
+            monitor.setup(air_monitor)
+            monitor.run(air_monitor, setup_params)
+            logger.warning(air_monitor.name + " - monitor started ...")
+
+        if seconds != None:
+            time.sleep(int(seconds))
+        else:
+            input("\tPress Enter to end capturing...")
+
+        # destroy monitor / get pcap
+        monitor.destroy(devices, air_monitors)
+        for air_monitor in air_monitors:
+            for log in air_monitor.logs:
+                head, tail = os.path.split(log)
+                output = output + "\t" + local_log_dir + "/" + tail + "\n"
+            air_monitor.get_logs(local_log_dir)
+        return output
+    except:
+        for air_monitor in air_monitors:
+            monitor.destroy(devices, air_monitors)
+            air_monitor.get_logs(local_log_dir)
+        raise
+
+def test_run_monitor(devices, setup_params, refs, duts, monitors):
+    """TC run standalone monitor"""
+    return run_monitor(devices, setup_params, refs, duts, monitors)