1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*cfb92d14SAndroid Build Coastguard Worker# 3*cfb92d14SAndroid Build Coastguard Worker# Copyright (c) 2016, The OpenThread Authors. 4*cfb92d14SAndroid Build Coastguard Worker# All rights reserved. 5*cfb92d14SAndroid Build Coastguard Worker# 6*cfb92d14SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 7*cfb92d14SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met: 8*cfb92d14SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright 9*cfb92d14SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer. 10*cfb92d14SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright 11*cfb92d14SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer in the 12*cfb92d14SAndroid Build Coastguard Worker# documentation and/or other materials provided with the distribution. 13*cfb92d14SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the 14*cfb92d14SAndroid Build Coastguard Worker# names of its contributors may be used to endorse or promote products 15*cfb92d14SAndroid Build Coastguard Worker# derived from this software without specific prior written permission. 16*cfb92d14SAndroid Build Coastguard Worker# 17*cfb92d14SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18*cfb92d14SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*cfb92d14SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*cfb92d14SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21*cfb92d14SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*cfb92d14SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*cfb92d14SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*cfb92d14SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*cfb92d14SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*cfb92d14SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*cfb92d14SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE. 28*cfb92d14SAndroid Build Coastguard Worker# 29*cfb92d14SAndroid Build Coastguard Worker 30*cfb92d14SAndroid Build Coastguard Workerimport json 31*cfb92d14SAndroid Build Coastguard Workerimport binascii 32*cfb92d14SAndroid Build Coastguard Workerimport ipaddress 33*cfb92d14SAndroid Build Coastguard Workerimport logging 34*cfb92d14SAndroid Build Coastguard Workerimport os 35*cfb92d14SAndroid Build Coastguard Workerimport re 36*cfb92d14SAndroid Build Coastguard Workerimport shlex 37*cfb92d14SAndroid Build Coastguard Workerimport socket 38*cfb92d14SAndroid Build Coastguard Workerimport subprocess 39*cfb92d14SAndroid Build Coastguard Workerimport sys 40*cfb92d14SAndroid Build Coastguard Workerimport time 41*cfb92d14SAndroid Build Coastguard Workerimport traceback 42*cfb92d14SAndroid Build Coastguard Workerimport typing 43*cfb92d14SAndroid Build Coastguard Workerimport unittest 44*cfb92d14SAndroid Build Coastguard Workerfrom ipaddress import IPv6Address, IPv6Network 45*cfb92d14SAndroid Build Coastguard Workerfrom typing import Union, Dict, Optional, List, Any 46*cfb92d14SAndroid Build Coastguard Worker 47*cfb92d14SAndroid Build Coastguard Workerimport pexpect 48*cfb92d14SAndroid Build Coastguard Workerimport pexpect.popen_spawn 49*cfb92d14SAndroid Build Coastguard Worker 50*cfb92d14SAndroid Build Coastguard Workerimport config 51*cfb92d14SAndroid Build Coastguard Workerimport simulator 52*cfb92d14SAndroid Build Coastguard Workerimport thread_cert 53*cfb92d14SAndroid Build Coastguard Worker 54*cfb92d14SAndroid Build Coastguard WorkerPORT_OFFSET = int(os.getenv('PORT_OFFSET', "0")) 55*cfb92d14SAndroid Build Coastguard Worker 56*cfb92d14SAndroid Build Coastguard WorkerINFRA_DNS64 = int(os.getenv('NAT64', 0)) 57*cfb92d14SAndroid Build Coastguard Worker 58*cfb92d14SAndroid Build Coastguard Worker 59*cfb92d14SAndroid Build Coastguard Workerclass OtbrDocker: 60*cfb92d14SAndroid Build Coastguard Worker RESET_DELAY = 3 61*cfb92d14SAndroid Build Coastguard Worker 62*cfb92d14SAndroid Build Coastguard Worker _socat_proc = None 63*cfb92d14SAndroid Build Coastguard Worker _ot_rcp_proc = None 64*cfb92d14SAndroid Build Coastguard Worker _docker_proc = None 65*cfb92d14SAndroid Build Coastguard Worker _border_routing_counters = None 66*cfb92d14SAndroid Build Coastguard Worker 67*cfb92d14SAndroid Build Coastguard Worker def __init__(self, nodeid: int, backbone_network: str, **kwargs): 68*cfb92d14SAndroid Build Coastguard Worker self.verbose = int(float(os.getenv('VERBOSE', 0))) 69*cfb92d14SAndroid Build Coastguard Worker 70*cfb92d14SAndroid Build Coastguard Worker assert backbone_network is not None 71*cfb92d14SAndroid Build Coastguard Worker self.backbone_network = backbone_network 72*cfb92d14SAndroid Build Coastguard Worker try: 73*cfb92d14SAndroid Build Coastguard Worker self._docker_name = config.OTBR_DOCKER_NAME_PREFIX + str(nodeid) 74*cfb92d14SAndroid Build Coastguard Worker self._prepare_ot_rcp_sim(nodeid) 75*cfb92d14SAndroid Build Coastguard Worker self._launch_docker() 76*cfb92d14SAndroid Build Coastguard Worker except Exception: 77*cfb92d14SAndroid Build Coastguard Worker traceback.print_exc() 78*cfb92d14SAndroid Build Coastguard Worker self.destroy() 79*cfb92d14SAndroid Build Coastguard Worker raise 80*cfb92d14SAndroid Build Coastguard Worker 81*cfb92d14SAndroid Build Coastguard Worker def _prepare_ot_rcp_sim(self, nodeid: int): 82*cfb92d14SAndroid Build Coastguard Worker self._socat_proc = subprocess.Popen(['socat', '-d', '-d', 'pty,raw,echo=0', 'pty,raw,echo=0'], 83*cfb92d14SAndroid Build Coastguard Worker stderr=subprocess.PIPE, 84*cfb92d14SAndroid Build Coastguard Worker stdin=subprocess.DEVNULL, 85*cfb92d14SAndroid Build Coastguard Worker stdout=subprocess.DEVNULL) 86*cfb92d14SAndroid Build Coastguard Worker 87*cfb92d14SAndroid Build Coastguard Worker line = self._socat_proc.stderr.readline().decode('ascii').strip() 88*cfb92d14SAndroid Build Coastguard Worker self._rcp_device_pty = rcp_device_pty = line[line.index('PTY is /dev') + 7:] 89*cfb92d14SAndroid Build Coastguard Worker line = self._socat_proc.stderr.readline().decode('ascii').strip() 90*cfb92d14SAndroid Build Coastguard Worker self._rcp_device = rcp_device = line[line.index('PTY is /dev') + 7:] 91*cfb92d14SAndroid Build Coastguard Worker logging.info(f"socat running: device PTY: {rcp_device_pty}, device: {rcp_device}") 92*cfb92d14SAndroid Build Coastguard Worker 93*cfb92d14SAndroid Build Coastguard Worker ot_rcp_path = self._get_ot_rcp_path() 94*cfb92d14SAndroid Build Coastguard Worker self._ot_rcp_proc = subprocess.Popen(f"{ot_rcp_path} {nodeid} > {rcp_device_pty} < {rcp_device_pty}", 95*cfb92d14SAndroid Build Coastguard Worker shell=True, 96*cfb92d14SAndroid Build Coastguard Worker stdin=subprocess.DEVNULL, 97*cfb92d14SAndroid Build Coastguard Worker stdout=subprocess.DEVNULL, 98*cfb92d14SAndroid Build Coastguard Worker stderr=subprocess.DEVNULL) 99*cfb92d14SAndroid Build Coastguard Worker 100*cfb92d14SAndroid Build Coastguard Worker try: 101*cfb92d14SAndroid Build Coastguard Worker self._ot_rcp_proc.wait(1) 102*cfb92d14SAndroid Build Coastguard Worker except subprocess.TimeoutExpired: 103*cfb92d14SAndroid Build Coastguard Worker # We expect ot-rcp not to quit in 1 second. 104*cfb92d14SAndroid Build Coastguard Worker pass 105*cfb92d14SAndroid Build Coastguard Worker else: 106*cfb92d14SAndroid Build Coastguard Worker raise Exception(f"ot-rcp {nodeid} exited unexpectedly!") 107*cfb92d14SAndroid Build Coastguard Worker 108*cfb92d14SAndroid Build Coastguard Worker def _get_ot_rcp_path(self) -> str: 109*cfb92d14SAndroid Build Coastguard Worker srcdir = os.environ['top_builddir'] 110*cfb92d14SAndroid Build Coastguard Worker path = '%s/examples/apps/ncp/ot-rcp' % srcdir 111*cfb92d14SAndroid Build Coastguard Worker logging.info("ot-rcp path: %s", path) 112*cfb92d14SAndroid Build Coastguard Worker return path 113*cfb92d14SAndroid Build Coastguard Worker 114*cfb92d14SAndroid Build Coastguard Worker def _launch_docker(self): 115*cfb92d14SAndroid Build Coastguard Worker logging.info(f'Docker image: {config.OTBR_DOCKER_IMAGE}') 116*cfb92d14SAndroid Build Coastguard Worker subprocess.check_call(f"docker rm -f {self._docker_name} || true", shell=True) 117*cfb92d14SAndroid Build Coastguard Worker CI_ENV = os.getenv('CI_ENV', '').split() 118*cfb92d14SAndroid Build Coastguard Worker dns = ['--dns=127.0.0.1'] if INFRA_DNS64 == 1 else ['--dns=8.8.8.8'] 119*cfb92d14SAndroid Build Coastguard Worker nat64_prefix = ['--nat64-prefix', '2001:db8:1:ffff::/96'] if INFRA_DNS64 == 1 else [] 120*cfb92d14SAndroid Build Coastguard Worker os.makedirs('/tmp/coverage/', exist_ok=True) 121*cfb92d14SAndroid Build Coastguard Worker 122*cfb92d14SAndroid Build Coastguard Worker cmd = ['docker', 'run'] + CI_ENV + [ 123*cfb92d14SAndroid Build Coastguard Worker '--rm', 124*cfb92d14SAndroid Build Coastguard Worker '--name', 125*cfb92d14SAndroid Build Coastguard Worker self._docker_name, 126*cfb92d14SAndroid Build Coastguard Worker '--network', 127*cfb92d14SAndroid Build Coastguard Worker self.backbone_network, 128*cfb92d14SAndroid Build Coastguard Worker ] + dns + [ 129*cfb92d14SAndroid Build Coastguard Worker '-i', 130*cfb92d14SAndroid Build Coastguard Worker '--sysctl', 131*cfb92d14SAndroid Build Coastguard Worker 'net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1', 132*cfb92d14SAndroid Build Coastguard Worker '--privileged', 133*cfb92d14SAndroid Build Coastguard Worker '--cap-add=NET_ADMIN', 134*cfb92d14SAndroid Build Coastguard Worker '--volume', 135*cfb92d14SAndroid Build Coastguard Worker f'{self._rcp_device}:/dev/ttyUSB0', 136*cfb92d14SAndroid Build Coastguard Worker '-v', 137*cfb92d14SAndroid Build Coastguard Worker '/tmp/coverage/:/tmp/coverage/', 138*cfb92d14SAndroid Build Coastguard Worker config.OTBR_DOCKER_IMAGE, 139*cfb92d14SAndroid Build Coastguard Worker '-B', 140*cfb92d14SAndroid Build Coastguard Worker config.BACKBONE_IFNAME, 141*cfb92d14SAndroid Build Coastguard Worker '--trel-url', 142*cfb92d14SAndroid Build Coastguard Worker f'trel://{config.BACKBONE_IFNAME}', 143*cfb92d14SAndroid Build Coastguard Worker ] + nat64_prefix 144*cfb92d14SAndroid Build Coastguard Worker logging.info(' '.join(cmd)) 145*cfb92d14SAndroid Build Coastguard Worker self._docker_proc = subprocess.Popen(cmd, 146*cfb92d14SAndroid Build Coastguard Worker stdin=subprocess.DEVNULL, 147*cfb92d14SAndroid Build Coastguard Worker stdout=sys.stdout if self.verbose else subprocess.DEVNULL, 148*cfb92d14SAndroid Build Coastguard Worker stderr=sys.stderr if self.verbose else subprocess.DEVNULL) 149*cfb92d14SAndroid Build Coastguard Worker 150*cfb92d14SAndroid Build Coastguard Worker launch_docker_deadline = time.time() + 300 151*cfb92d14SAndroid Build Coastguard Worker launch_ok = False 152*cfb92d14SAndroid Build Coastguard Worker 153*cfb92d14SAndroid Build Coastguard Worker while time.time() < launch_docker_deadline: 154*cfb92d14SAndroid Build Coastguard Worker try: 155*cfb92d14SAndroid Build Coastguard Worker subprocess.check_call(f'docker exec -i {self._docker_name} ot-ctl state', shell=True) 156*cfb92d14SAndroid Build Coastguard Worker launch_ok = True 157*cfb92d14SAndroid Build Coastguard Worker logging.info("OTBR Docker %s on %s Is Ready!", self._docker_name, self.backbone_network) 158*cfb92d14SAndroid Build Coastguard Worker break 159*cfb92d14SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 160*cfb92d14SAndroid Build Coastguard Worker time.sleep(5) 161*cfb92d14SAndroid Build Coastguard Worker continue 162*cfb92d14SAndroid Build Coastguard Worker 163*cfb92d14SAndroid Build Coastguard Worker assert launch_ok 164*cfb92d14SAndroid Build Coastguard Worker 165*cfb92d14SAndroid Build Coastguard Worker self.start_ot_ctl() 166*cfb92d14SAndroid Build Coastguard Worker 167*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 168*cfb92d14SAndroid Build Coastguard Worker return f'OtbrDocker<{self.nodeid}>' 169*cfb92d14SAndroid Build Coastguard Worker 170*cfb92d14SAndroid Build Coastguard Worker def start_otbr_service(self): 171*cfb92d14SAndroid Build Coastguard Worker self.bash('service otbr-agent start') 172*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(3) 173*cfb92d14SAndroid Build Coastguard Worker self.start_ot_ctl() 174*cfb92d14SAndroid Build Coastguard Worker 175*cfb92d14SAndroid Build Coastguard Worker def stop_otbr_service(self): 176*cfb92d14SAndroid Build Coastguard Worker self.stop_ot_ctl() 177*cfb92d14SAndroid Build Coastguard Worker self.bash('service otbr-agent stop') 178*cfb92d14SAndroid Build Coastguard Worker 179*cfb92d14SAndroid Build Coastguard Worker def stop_mdns_service(self): 180*cfb92d14SAndroid Build Coastguard Worker self.bash('service avahi-daemon stop; service mdns stop; !(cat /proc/net/udp | grep -i :14E9)') 181*cfb92d14SAndroid Build Coastguard Worker 182*cfb92d14SAndroid Build Coastguard Worker def start_mdns_service(self): 183*cfb92d14SAndroid Build Coastguard Worker self.bash('service avahi-daemon start; service mdns start; cat /proc/net/udp | grep -i :14E9') 184*cfb92d14SAndroid Build Coastguard Worker 185*cfb92d14SAndroid Build Coastguard Worker def start_ot_ctl(self): 186*cfb92d14SAndroid Build Coastguard Worker cmd = f'docker exec -i {self._docker_name} ot-ctl' 187*cfb92d14SAndroid Build Coastguard Worker self.pexpect = pexpect.popen_spawn.PopenSpawn(cmd, timeout=30) 188*cfb92d14SAndroid Build Coastguard Worker if self.verbose: 189*cfb92d14SAndroid Build Coastguard Worker self.pexpect.logfile_read = sys.stdout.buffer 190*cfb92d14SAndroid Build Coastguard Worker 191*cfb92d14SAndroid Build Coastguard Worker # Add delay to ensure that the process is ready to receive commands. 192*cfb92d14SAndroid Build Coastguard Worker timeout = 0.4 193*cfb92d14SAndroid Build Coastguard Worker while timeout > 0: 194*cfb92d14SAndroid Build Coastguard Worker self.pexpect.send('\r\n') 195*cfb92d14SAndroid Build Coastguard Worker try: 196*cfb92d14SAndroid Build Coastguard Worker self.pexpect.expect('> ', timeout=0.1) 197*cfb92d14SAndroid Build Coastguard Worker break 198*cfb92d14SAndroid Build Coastguard Worker except pexpect.TIMEOUT: 199*cfb92d14SAndroid Build Coastguard Worker timeout -= 0.1 200*cfb92d14SAndroid Build Coastguard Worker 201*cfb92d14SAndroid Build Coastguard Worker def stop_ot_ctl(self): 202*cfb92d14SAndroid Build Coastguard Worker self.pexpect.sendeof() 203*cfb92d14SAndroid Build Coastguard Worker self.pexpect.wait() 204*cfb92d14SAndroid Build Coastguard Worker self.pexpect.proc.kill() 205*cfb92d14SAndroid Build Coastguard Worker 206*cfb92d14SAndroid Build Coastguard Worker def reserve_udp_port(self, port): 207*cfb92d14SAndroid Build Coastguard Worker self.bash(f'socat -u UDP6-LISTEN:{port},bindtodevice=wpan0 - &') 208*cfb92d14SAndroid Build Coastguard Worker 209*cfb92d14SAndroid Build Coastguard Worker def destroy(self): 210*cfb92d14SAndroid Build Coastguard Worker logging.info("Destroying %s", self) 211*cfb92d14SAndroid Build Coastguard Worker self._shutdown_docker() 212*cfb92d14SAndroid Build Coastguard Worker self._shutdown_ot_rcp() 213*cfb92d14SAndroid Build Coastguard Worker self._shutdown_socat() 214*cfb92d14SAndroid Build Coastguard Worker 215*cfb92d14SAndroid Build Coastguard Worker def _shutdown_docker(self): 216*cfb92d14SAndroid Build Coastguard Worker if self._docker_proc is None: 217*cfb92d14SAndroid Build Coastguard Worker return 218*cfb92d14SAndroid Build Coastguard Worker 219*cfb92d14SAndroid Build Coastguard Worker try: 220*cfb92d14SAndroid Build Coastguard Worker COVERAGE = int(os.getenv('COVERAGE', '0')) 221*cfb92d14SAndroid Build Coastguard Worker OTBR_COVERAGE = int(os.getenv('OTBR_COVERAGE', '0')) 222*cfb92d14SAndroid Build Coastguard Worker test_name = os.getenv('TEST_NAME') 223*cfb92d14SAndroid Build Coastguard Worker unique_node_id = f'{test_name}-{PORT_OFFSET}-{self.nodeid}' 224*cfb92d14SAndroid Build Coastguard Worker 225*cfb92d14SAndroid Build Coastguard Worker if COVERAGE or OTBR_COVERAGE: 226*cfb92d14SAndroid Build Coastguard Worker self.bash('service otbr-agent stop') 227*cfb92d14SAndroid Build Coastguard Worker 228*cfb92d14SAndroid Build Coastguard Worker cov_file_path = f'/tmp/coverage/coverage-{unique_node_id}.info' 229*cfb92d14SAndroid Build Coastguard Worker # Upload OTBR code coverage if OTBR_COVERAGE=1, otherwise OpenThread code coverage. 230*cfb92d14SAndroid Build Coastguard Worker if OTBR_COVERAGE: 231*cfb92d14SAndroid Build Coastguard Worker codecov_cmd = f'lcov --directory . --capture --output-file {cov_file_path}' 232*cfb92d14SAndroid Build Coastguard Worker else: 233*cfb92d14SAndroid Build Coastguard Worker codecov_cmd = ('lcov --directory build/otbr/third_party/openthread/repo --capture ' 234*cfb92d14SAndroid Build Coastguard Worker f'--output-file {cov_file_path}') 235*cfb92d14SAndroid Build Coastguard Worker 236*cfb92d14SAndroid Build Coastguard Worker self.bash(codecov_cmd) 237*cfb92d14SAndroid Build Coastguard Worker 238*cfb92d14SAndroid Build Coastguard Worker copyCore = subprocess.run(f'docker cp {self._docker_name}:/core ./coredump_{unique_node_id}', shell=True) 239*cfb92d14SAndroid Build Coastguard Worker if copyCore.returncode == 0: 240*cfb92d14SAndroid Build Coastguard Worker subprocess.check_call( 241*cfb92d14SAndroid Build Coastguard Worker f'docker cp {self._docker_name}:/usr/sbin/otbr-agent ./otbr-agent_{unique_node_id}', shell=True) 242*cfb92d14SAndroid Build Coastguard Worker 243*cfb92d14SAndroid Build Coastguard Worker finally: 244*cfb92d14SAndroid Build Coastguard Worker subprocess.check_call(f"docker rm -f {self._docker_name}", shell=True) 245*cfb92d14SAndroid Build Coastguard Worker self._docker_proc.wait() 246*cfb92d14SAndroid Build Coastguard Worker del self._docker_proc 247*cfb92d14SAndroid Build Coastguard Worker 248*cfb92d14SAndroid Build Coastguard Worker def _shutdown_ot_rcp(self): 249*cfb92d14SAndroid Build Coastguard Worker if self._ot_rcp_proc is not None: 250*cfb92d14SAndroid Build Coastguard Worker self._ot_rcp_proc.kill() 251*cfb92d14SAndroid Build Coastguard Worker self._ot_rcp_proc.wait() 252*cfb92d14SAndroid Build Coastguard Worker del self._ot_rcp_proc 253*cfb92d14SAndroid Build Coastguard Worker 254*cfb92d14SAndroid Build Coastguard Worker def _shutdown_socat(self): 255*cfb92d14SAndroid Build Coastguard Worker if self._socat_proc is not None: 256*cfb92d14SAndroid Build Coastguard Worker self._socat_proc.stderr.close() 257*cfb92d14SAndroid Build Coastguard Worker self._socat_proc.kill() 258*cfb92d14SAndroid Build Coastguard Worker self._socat_proc.wait() 259*cfb92d14SAndroid Build Coastguard Worker del self._socat_proc 260*cfb92d14SAndroid Build Coastguard Worker 261*cfb92d14SAndroid Build Coastguard Worker def bash(self, cmd: str, encoding='ascii') -> List[str]: 262*cfb92d14SAndroid Build Coastguard Worker logging.info("%s $ %s", self, cmd) 263*cfb92d14SAndroid Build Coastguard Worker proc = subprocess.Popen(['docker', 'exec', '-i', self._docker_name, 'bash', '-c', cmd], 264*cfb92d14SAndroid Build Coastguard Worker stdin=subprocess.DEVNULL, 265*cfb92d14SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 266*cfb92d14SAndroid Build Coastguard Worker stderr=sys.stderr, 267*cfb92d14SAndroid Build Coastguard Worker encoding=encoding) 268*cfb92d14SAndroid Build Coastguard Worker 269*cfb92d14SAndroid Build Coastguard Worker with proc: 270*cfb92d14SAndroid Build Coastguard Worker 271*cfb92d14SAndroid Build Coastguard Worker lines = [] 272*cfb92d14SAndroid Build Coastguard Worker 273*cfb92d14SAndroid Build Coastguard Worker while True: 274*cfb92d14SAndroid Build Coastguard Worker line = proc.stdout.readline() 275*cfb92d14SAndroid Build Coastguard Worker 276*cfb92d14SAndroid Build Coastguard Worker if not line: 277*cfb92d14SAndroid Build Coastguard Worker break 278*cfb92d14SAndroid Build Coastguard Worker 279*cfb92d14SAndroid Build Coastguard Worker lines.append(line) 280*cfb92d14SAndroid Build Coastguard Worker logging.info("%s $ %r", self, line.rstrip('\r\n')) 281*cfb92d14SAndroid Build Coastguard Worker 282*cfb92d14SAndroid Build Coastguard Worker proc.wait() 283*cfb92d14SAndroid Build Coastguard Worker 284*cfb92d14SAndroid Build Coastguard Worker if proc.returncode != 0: 285*cfb92d14SAndroid Build Coastguard Worker raise subprocess.CalledProcessError(proc.returncode, cmd, ''.join(lines)) 286*cfb92d14SAndroid Build Coastguard Worker else: 287*cfb92d14SAndroid Build Coastguard Worker return lines 288*cfb92d14SAndroid Build Coastguard Worker 289*cfb92d14SAndroid Build Coastguard Worker def dns_dig(self, server: str, name: str, qtype: str): 290*cfb92d14SAndroid Build Coastguard Worker """ 291*cfb92d14SAndroid Build Coastguard Worker Run dig command to query a DNS server. 292*cfb92d14SAndroid Build Coastguard Worker 293*cfb92d14SAndroid Build Coastguard Worker Args: 294*cfb92d14SAndroid Build Coastguard Worker server: the server address. 295*cfb92d14SAndroid Build Coastguard Worker name: the name to query. 296*cfb92d14SAndroid Build Coastguard Worker qtype: the query type (e.g. AAAA, PTR, TXT, SRV). 297*cfb92d14SAndroid Build Coastguard Worker 298*cfb92d14SAndroid Build Coastguard Worker Returns: 299*cfb92d14SAndroid Build Coastguard Worker The dig result similar as below: 300*cfb92d14SAndroid Build Coastguard Worker { 301*cfb92d14SAndroid Build Coastguard Worker "opcode": "QUERY", 302*cfb92d14SAndroid Build Coastguard Worker "status": "NOERROR", 303*cfb92d14SAndroid Build Coastguard Worker "id": "64144", 304*cfb92d14SAndroid Build Coastguard Worker "QUESTION": [ 305*cfb92d14SAndroid Build Coastguard Worker ('google.com.', 'IN', 'AAAA') 306*cfb92d14SAndroid Build Coastguard Worker ], 307*cfb92d14SAndroid Build Coastguard Worker "ANSWER": [ 308*cfb92d14SAndroid Build Coastguard Worker ('google.com.', 107, 'IN', 'AAAA', '2404:6800:4008:c00::71'), 309*cfb92d14SAndroid Build Coastguard Worker ('google.com.', 107, 'IN', 'AAAA', '2404:6800:4008:c00::8a'), 310*cfb92d14SAndroid Build Coastguard Worker ('google.com.', 107, 'IN', 'AAAA', '2404:6800:4008:c00::66'), 311*cfb92d14SAndroid Build Coastguard Worker ('google.com.', 107, 'IN', 'AAAA', '2404:6800:4008:c00::8b'), 312*cfb92d14SAndroid Build Coastguard Worker ], 313*cfb92d14SAndroid Build Coastguard Worker "ADDITIONAL": [ 314*cfb92d14SAndroid Build Coastguard Worker ], 315*cfb92d14SAndroid Build Coastguard Worker } 316*cfb92d14SAndroid Build Coastguard Worker """ 317*cfb92d14SAndroid Build Coastguard Worker output = self.bash(f'dig -6 @{server} \'{name}\' {qtype}', encoding='raw_unicode_escape') 318*cfb92d14SAndroid Build Coastguard Worker 319*cfb92d14SAndroid Build Coastguard Worker section = None 320*cfb92d14SAndroid Build Coastguard Worker dig_result = { 321*cfb92d14SAndroid Build Coastguard Worker 'QUESTION': [], 322*cfb92d14SAndroid Build Coastguard Worker 'ANSWER': [], 323*cfb92d14SAndroid Build Coastguard Worker 'ADDITIONAL': [], 324*cfb92d14SAndroid Build Coastguard Worker } 325*cfb92d14SAndroid Build Coastguard Worker 326*cfb92d14SAndroid Build Coastguard Worker for line in output: 327*cfb92d14SAndroid Build Coastguard Worker line = line.strip() 328*cfb92d14SAndroid Build Coastguard Worker 329*cfb92d14SAndroid Build Coastguard Worker if line.startswith(';; ->>HEADER<<- '): 330*cfb92d14SAndroid Build Coastguard Worker headers = line[len(';; ->>HEADER<<- '):].split(', ') 331*cfb92d14SAndroid Build Coastguard Worker for header in headers: 332*cfb92d14SAndroid Build Coastguard Worker key, val = header.split(': ') 333*cfb92d14SAndroid Build Coastguard Worker dig_result[key] = val 334*cfb92d14SAndroid Build Coastguard Worker 335*cfb92d14SAndroid Build Coastguard Worker continue 336*cfb92d14SAndroid Build Coastguard Worker 337*cfb92d14SAndroid Build Coastguard Worker if line == ';; QUESTION SECTION:': 338*cfb92d14SAndroid Build Coastguard Worker section = 'QUESTION' 339*cfb92d14SAndroid Build Coastguard Worker continue 340*cfb92d14SAndroid Build Coastguard Worker elif line == ';; ANSWER SECTION:': 341*cfb92d14SAndroid Build Coastguard Worker section = 'ANSWER' 342*cfb92d14SAndroid Build Coastguard Worker continue 343*cfb92d14SAndroid Build Coastguard Worker elif line == ';; ADDITIONAL SECTION:': 344*cfb92d14SAndroid Build Coastguard Worker section = 'ADDITIONAL' 345*cfb92d14SAndroid Build Coastguard Worker continue 346*cfb92d14SAndroid Build Coastguard Worker elif section and not line: 347*cfb92d14SAndroid Build Coastguard Worker section = None 348*cfb92d14SAndroid Build Coastguard Worker continue 349*cfb92d14SAndroid Build Coastguard Worker 350*cfb92d14SAndroid Build Coastguard Worker if section: 351*cfb92d14SAndroid Build Coastguard Worker assert line 352*cfb92d14SAndroid Build Coastguard Worker 353*cfb92d14SAndroid Build Coastguard Worker if section == 'QUESTION': 354*cfb92d14SAndroid Build Coastguard Worker assert line.startswith(';') 355*cfb92d14SAndroid Build Coastguard Worker line = line[1:] 356*cfb92d14SAndroid Build Coastguard Worker record = list(line.split()) 357*cfb92d14SAndroid Build Coastguard Worker 358*cfb92d14SAndroid Build Coastguard Worker if section == 'QUESTION': 359*cfb92d14SAndroid Build Coastguard Worker if record[2] in ('SRV', 'TXT'): 360*cfb92d14SAndroid Build Coastguard Worker record[0] = self.__unescape_dns_instance_name(record[0]) 361*cfb92d14SAndroid Build Coastguard Worker else: 362*cfb92d14SAndroid Build Coastguard Worker record[1] = int(record[1]) 363*cfb92d14SAndroid Build Coastguard Worker if record[3] == 'SRV': 364*cfb92d14SAndroid Build Coastguard Worker record[0] = self.__unescape_dns_instance_name(record[0]) 365*cfb92d14SAndroid Build Coastguard Worker record[4], record[5], record[6] = map(int, [record[4], record[5], record[6]]) 366*cfb92d14SAndroid Build Coastguard Worker elif record[3] == 'TXT': 367*cfb92d14SAndroid Build Coastguard Worker record[0] = self.__unescape_dns_instance_name(record[0]) 368*cfb92d14SAndroid Build Coastguard Worker record[4:] = [self.__parse_dns_dig_txt(line)] 369*cfb92d14SAndroid Build Coastguard Worker elif record[3] == 'PTR': 370*cfb92d14SAndroid Build Coastguard Worker record[4] = self.__unescape_dns_instance_name(record[4]) 371*cfb92d14SAndroid Build Coastguard Worker 372*cfb92d14SAndroid Build Coastguard Worker dig_result[section].append(tuple(record)) 373*cfb92d14SAndroid Build Coastguard Worker 374*cfb92d14SAndroid Build Coastguard Worker return dig_result 375*cfb92d14SAndroid Build Coastguard Worker 376*cfb92d14SAndroid Build Coastguard Worker def call_dbus_method(self, *args): 377*cfb92d14SAndroid Build Coastguard Worker args = shlex.join([args[0], args[1], json.dumps(args[2:])]) 378*cfb92d14SAndroid Build Coastguard Worker return json.loads( 379*cfb92d14SAndroid Build Coastguard Worker self.bash(f'python3 /app/third_party/openthread/repo/tests/scripts/thread-cert/call_dbus_method.py {args}') 380*cfb92d14SAndroid Build Coastguard Worker [0]) 381*cfb92d14SAndroid Build Coastguard Worker 382*cfb92d14SAndroid Build Coastguard Worker def get_dbus_property(self, property_name): 383*cfb92d14SAndroid Build Coastguard Worker return self.call_dbus_method('org.freedesktop.DBus.Properties', 'Get', 'io.openthread.BorderRouter', 384*cfb92d14SAndroid Build Coastguard Worker property_name) 385*cfb92d14SAndroid Build Coastguard Worker 386*cfb92d14SAndroid Build Coastguard Worker def set_dbus_property(self, property_name, property_value): 387*cfb92d14SAndroid Build Coastguard Worker return self.call_dbus_method('org.freedesktop.DBus.Properties', 'Set', 'io.openthread.BorderRouter', 388*cfb92d14SAndroid Build Coastguard Worker property_name, property_value) 389*cfb92d14SAndroid Build Coastguard Worker 390*cfb92d14SAndroid Build Coastguard Worker def get_border_routing_counters(self): 391*cfb92d14SAndroid Build Coastguard Worker counters = self.get_dbus_property('BorderRoutingCounters') 392*cfb92d14SAndroid Build Coastguard Worker counters = { 393*cfb92d14SAndroid Build Coastguard Worker 'inbound_unicast': counters[0], 394*cfb92d14SAndroid Build Coastguard Worker 'inbound_multicast': counters[1], 395*cfb92d14SAndroid Build Coastguard Worker 'outbound_unicast': counters[2], 396*cfb92d14SAndroid Build Coastguard Worker 'outbound_multicast': counters[3], 397*cfb92d14SAndroid Build Coastguard Worker 'ra_rx': counters[4], 398*cfb92d14SAndroid Build Coastguard Worker 'ra_tx_success': counters[5], 399*cfb92d14SAndroid Build Coastguard Worker 'ra_tx_failure': counters[6], 400*cfb92d14SAndroid Build Coastguard Worker 'rs_rx': counters[7], 401*cfb92d14SAndroid Build Coastguard Worker 'rs_tx_success': counters[8], 402*cfb92d14SAndroid Build Coastguard Worker 'rs_tx_failure': counters[9], 403*cfb92d14SAndroid Build Coastguard Worker } 404*cfb92d14SAndroid Build Coastguard Worker logging.info(f'border routing counters: {counters}') 405*cfb92d14SAndroid Build Coastguard Worker return counters 406*cfb92d14SAndroid Build Coastguard Worker 407*cfb92d14SAndroid Build Coastguard Worker def _process_traffic_counters(self, counter): 408*cfb92d14SAndroid Build Coastguard Worker return { 409*cfb92d14SAndroid Build Coastguard Worker '4to6': { 410*cfb92d14SAndroid Build Coastguard Worker 'packets': counter[0], 411*cfb92d14SAndroid Build Coastguard Worker 'bytes': counter[1], 412*cfb92d14SAndroid Build Coastguard Worker }, 413*cfb92d14SAndroid Build Coastguard Worker '6to4': { 414*cfb92d14SAndroid Build Coastguard Worker 'packets': counter[2], 415*cfb92d14SAndroid Build Coastguard Worker 'bytes': counter[3], 416*cfb92d14SAndroid Build Coastguard Worker } 417*cfb92d14SAndroid Build Coastguard Worker } 418*cfb92d14SAndroid Build Coastguard Worker 419*cfb92d14SAndroid Build Coastguard Worker def _process_packet_counters(self, counter): 420*cfb92d14SAndroid Build Coastguard Worker return {'4to6': {'packets': counter[0]}, '6to4': {'packets': counter[1]}} 421*cfb92d14SAndroid Build Coastguard Worker 422*cfb92d14SAndroid Build Coastguard Worker def nat64_set_enabled(self, enable): 423*cfb92d14SAndroid Build Coastguard Worker return self.call_dbus_method('io.openthread.BorderRouter', 'SetNat64Enabled', enable) 424*cfb92d14SAndroid Build Coastguard Worker 425*cfb92d14SAndroid Build Coastguard Worker def activate_ephemeral_key_mode(self, lifetime): 426*cfb92d14SAndroid Build Coastguard Worker return self.call_dbus_method('io.openthread.BorderRouter', 'ActivateEphemeralKeyMode', lifetime) 427*cfb92d14SAndroid Build Coastguard Worker 428*cfb92d14SAndroid Build Coastguard Worker def deactivate_ephemeral_key_mode(self): 429*cfb92d14SAndroid Build Coastguard Worker return self.call_dbus_method('io.openthread.BorderRouter', 'DeactivateEphemeralKeyMode') 430*cfb92d14SAndroid Build Coastguard Worker 431*cfb92d14SAndroid Build Coastguard Worker @property 432*cfb92d14SAndroid Build Coastguard Worker def nat64_cidr(self): 433*cfb92d14SAndroid Build Coastguard Worker self.send_command('nat64 cidr') 434*cfb92d14SAndroid Build Coastguard Worker cidr = self._expect_command_output()[0].strip() 435*cfb92d14SAndroid Build Coastguard Worker return ipaddress.IPv4Network(cidr, strict=False) 436*cfb92d14SAndroid Build Coastguard Worker 437*cfb92d14SAndroid Build Coastguard Worker @nat64_cidr.setter 438*cfb92d14SAndroid Build Coastguard Worker def nat64_cidr(self, cidr: ipaddress.IPv4Network): 439*cfb92d14SAndroid Build Coastguard Worker if not isinstance(cidr, ipaddress.IPv4Network): 440*cfb92d14SAndroid Build Coastguard Worker raise ValueError("cidr is expected to be an instance of ipaddress.IPv4Network") 441*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'nat64 cidr {cidr}') 442*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 443*cfb92d14SAndroid Build Coastguard Worker 444*cfb92d14SAndroid Build Coastguard Worker @property 445*cfb92d14SAndroid Build Coastguard Worker def nat64_state(self): 446*cfb92d14SAndroid Build Coastguard Worker state = self.get_dbus_property('Nat64State') 447*cfb92d14SAndroid Build Coastguard Worker return {'PrefixManager': state[0], 'Translator': state[1]} 448*cfb92d14SAndroid Build Coastguard Worker 449*cfb92d14SAndroid Build Coastguard Worker @property 450*cfb92d14SAndroid Build Coastguard Worker def nat64_mappings(self): 451*cfb92d14SAndroid Build Coastguard Worker return [{ 452*cfb92d14SAndroid Build Coastguard Worker 'id': row[0], 453*cfb92d14SAndroid Build Coastguard Worker 'ip4': row[1], 454*cfb92d14SAndroid Build Coastguard Worker 'ip6': row[2], 455*cfb92d14SAndroid Build Coastguard Worker 'expiry': row[3], 456*cfb92d14SAndroid Build Coastguard Worker 'counters': { 457*cfb92d14SAndroid Build Coastguard Worker 'total': self._process_traffic_counters(row[4][0]), 458*cfb92d14SAndroid Build Coastguard Worker 'ICMP': self._process_traffic_counters(row[4][1]), 459*cfb92d14SAndroid Build Coastguard Worker 'UDP': self._process_traffic_counters(row[4][2]), 460*cfb92d14SAndroid Build Coastguard Worker 'TCP': self._process_traffic_counters(row[4][3]), 461*cfb92d14SAndroid Build Coastguard Worker } 462*cfb92d14SAndroid Build Coastguard Worker } for row in self.get_dbus_property('Nat64Mappings')] 463*cfb92d14SAndroid Build Coastguard Worker 464*cfb92d14SAndroid Build Coastguard Worker @property 465*cfb92d14SAndroid Build Coastguard Worker def nat64_counters(self): 466*cfb92d14SAndroid Build Coastguard Worker res_error = self.get_dbus_property('Nat64ErrorCounters') 467*cfb92d14SAndroid Build Coastguard Worker res_proto = self.get_dbus_property('Nat64ProtocolCounters') 468*cfb92d14SAndroid Build Coastguard Worker return { 469*cfb92d14SAndroid Build Coastguard Worker 'protocol': { 470*cfb92d14SAndroid Build Coastguard Worker 'Total': self._process_traffic_counters(res_proto[0]), 471*cfb92d14SAndroid Build Coastguard Worker 'ICMP': self._process_traffic_counters(res_proto[1]), 472*cfb92d14SAndroid Build Coastguard Worker 'UDP': self._process_traffic_counters(res_proto[2]), 473*cfb92d14SAndroid Build Coastguard Worker 'TCP': self._process_traffic_counters(res_proto[3]), 474*cfb92d14SAndroid Build Coastguard Worker }, 475*cfb92d14SAndroid Build Coastguard Worker 'errors': { 476*cfb92d14SAndroid Build Coastguard Worker 'Unknown': self._process_packet_counters(res_error[0]), 477*cfb92d14SAndroid Build Coastguard Worker 'Illegal Pkt': self._process_packet_counters(res_error[1]), 478*cfb92d14SAndroid Build Coastguard Worker 'Unsup Proto': self._process_packet_counters(res_error[2]), 479*cfb92d14SAndroid Build Coastguard Worker 'No Mapping': self._process_packet_counters(res_error[3]), 480*cfb92d14SAndroid Build Coastguard Worker } 481*cfb92d14SAndroid Build Coastguard Worker } 482*cfb92d14SAndroid Build Coastguard Worker 483*cfb92d14SAndroid Build Coastguard Worker @property 484*cfb92d14SAndroid Build Coastguard Worker def nat64_traffic_counters(self): 485*cfb92d14SAndroid Build Coastguard Worker res = self.get_dbus_property('Nat64TrafficCounters') 486*cfb92d14SAndroid Build Coastguard Worker return { 487*cfb92d14SAndroid Build Coastguard Worker 'Total': self._process_traffic_counters(res[0]), 488*cfb92d14SAndroid Build Coastguard Worker 'ICMP': self._process_traffic_counters(res[1]), 489*cfb92d14SAndroid Build Coastguard Worker 'UDP': self._process_traffic_counters(res[2]), 490*cfb92d14SAndroid Build Coastguard Worker 'TCP': self._process_traffic_counters(res[3]), 491*cfb92d14SAndroid Build Coastguard Worker } 492*cfb92d14SAndroid Build Coastguard Worker 493*cfb92d14SAndroid Build Coastguard Worker @property 494*cfb92d14SAndroid Build Coastguard Worker def dns_upstream_query_state(self): 495*cfb92d14SAndroid Build Coastguard Worker return bool(self.get_dbus_property('DnsUpstreamQueryState')) 496*cfb92d14SAndroid Build Coastguard Worker 497*cfb92d14SAndroid Build Coastguard Worker @dns_upstream_query_state.setter 498*cfb92d14SAndroid Build Coastguard Worker def dns_upstream_query_state(self, value): 499*cfb92d14SAndroid Build Coastguard Worker if type(value) is not bool: 500*cfb92d14SAndroid Build Coastguard Worker raise ValueError("dns_upstream_query_state must be a bool") 501*cfb92d14SAndroid Build Coastguard Worker return self.set_dbus_property('DnsUpstreamQueryState', value) 502*cfb92d14SAndroid Build Coastguard Worker 503*cfb92d14SAndroid Build Coastguard Worker @property 504*cfb92d14SAndroid Build Coastguard Worker def ephemeral_key_enabled(self): 505*cfb92d14SAndroid Build Coastguard Worker return bool(self.get_dbus_property('EphemeralKeyEnabled')) 506*cfb92d14SAndroid Build Coastguard Worker 507*cfb92d14SAndroid Build Coastguard Worker @ephemeral_key_enabled.setter 508*cfb92d14SAndroid Build Coastguard Worker def ephemeral_key_enabled(self, value): 509*cfb92d14SAndroid Build Coastguard Worker if type(value) is not bool: 510*cfb92d14SAndroid Build Coastguard Worker raise ValueError("ephemeral_key_enabled must be a bool") 511*cfb92d14SAndroid Build Coastguard Worker return self.set_dbus_property('EphemeralKeyEnabled', value) 512*cfb92d14SAndroid Build Coastguard Worker 513*cfb92d14SAndroid Build Coastguard Worker def read_border_routing_counters_delta(self): 514*cfb92d14SAndroid Build Coastguard Worker old_counters = self._border_routing_counters 515*cfb92d14SAndroid Build Coastguard Worker new_counters = self.get_border_routing_counters() 516*cfb92d14SAndroid Build Coastguard Worker self._border_routing_counters = new_counters 517*cfb92d14SAndroid Build Coastguard Worker delta_counters = {} 518*cfb92d14SAndroid Build Coastguard Worker if old_counters is None: 519*cfb92d14SAndroid Build Coastguard Worker delta_counters = new_counters 520*cfb92d14SAndroid Build Coastguard Worker else: 521*cfb92d14SAndroid Build Coastguard Worker for i in ('inbound', 'outbound'): 522*cfb92d14SAndroid Build Coastguard Worker for j in ('unicast', 'multicast'): 523*cfb92d14SAndroid Build Coastguard Worker key = f'{i}_{j}' 524*cfb92d14SAndroid Build Coastguard Worker assert (key in old_counters) 525*cfb92d14SAndroid Build Coastguard Worker assert (key in new_counters) 526*cfb92d14SAndroid Build Coastguard Worker value = [new_counters[key][0] - old_counters[key][0], new_counters[key][1] - old_counters[key][1]] 527*cfb92d14SAndroid Build Coastguard Worker delta_counters[key] = value 528*cfb92d14SAndroid Build Coastguard Worker delta_counters = { 529*cfb92d14SAndroid Build Coastguard Worker key: value for key, value in delta_counters.items() if not isinstance(value, int) and value[0] and value[1] 530*cfb92d14SAndroid Build Coastguard Worker } 531*cfb92d14SAndroid Build Coastguard Worker 532*cfb92d14SAndroid Build Coastguard Worker return delta_counters 533*cfb92d14SAndroid Build Coastguard Worker 534*cfb92d14SAndroid Build Coastguard Worker @staticmethod 535*cfb92d14SAndroid Build Coastguard Worker def __unescape_dns_instance_name(name: str) -> str: 536*cfb92d14SAndroid Build Coastguard Worker new_name = [] 537*cfb92d14SAndroid Build Coastguard Worker i = 0 538*cfb92d14SAndroid Build Coastguard Worker while i < len(name): 539*cfb92d14SAndroid Build Coastguard Worker c = name[i] 540*cfb92d14SAndroid Build Coastguard Worker 541*cfb92d14SAndroid Build Coastguard Worker if c == '\\': 542*cfb92d14SAndroid Build Coastguard Worker assert i + 1 < len(name), name 543*cfb92d14SAndroid Build Coastguard Worker if name[i + 1].isdigit(): 544*cfb92d14SAndroid Build Coastguard Worker assert i + 3 < len(name) and name[i + 2].isdigit() and name[i + 3].isdigit(), name 545*cfb92d14SAndroid Build Coastguard Worker new_name.append(chr(int(name[i + 1:i + 4]))) 546*cfb92d14SAndroid Build Coastguard Worker i += 3 547*cfb92d14SAndroid Build Coastguard Worker else: 548*cfb92d14SAndroid Build Coastguard Worker new_name.append(name[i + 1]) 549*cfb92d14SAndroid Build Coastguard Worker i += 1 550*cfb92d14SAndroid Build Coastguard Worker else: 551*cfb92d14SAndroid Build Coastguard Worker new_name.append(c) 552*cfb92d14SAndroid Build Coastguard Worker 553*cfb92d14SAndroid Build Coastguard Worker i += 1 554*cfb92d14SAndroid Build Coastguard Worker 555*cfb92d14SAndroid Build Coastguard Worker return ''.join(new_name) 556*cfb92d14SAndroid Build Coastguard Worker 557*cfb92d14SAndroid Build Coastguard Worker def __parse_dns_dig_txt(self, line: str): 558*cfb92d14SAndroid Build Coastguard Worker # Example TXT entry: 559*cfb92d14SAndroid Build Coastguard Worker # "xp=\\000\\013\\184\\000\\000\\000\\000\\000" 560*cfb92d14SAndroid Build Coastguard Worker txt = {} 561*cfb92d14SAndroid Build Coastguard Worker for entry in re.findall(r'"((?:[^\\]|\\.)*?)"', line): 562*cfb92d14SAndroid Build Coastguard Worker if entry == "": 563*cfb92d14SAndroid Build Coastguard Worker continue 564*cfb92d14SAndroid Build Coastguard Worker 565*cfb92d14SAndroid Build Coastguard Worker k, v = entry.split('=', 1) 566*cfb92d14SAndroid Build Coastguard Worker txt[k] = v 567*cfb92d14SAndroid Build Coastguard Worker 568*cfb92d14SAndroid Build Coastguard Worker return txt 569*cfb92d14SAndroid Build Coastguard Worker 570*cfb92d14SAndroid Build Coastguard Worker def _setup_sysctl(self): 571*cfb92d14SAndroid Build Coastguard Worker self.bash(f'sysctl net.ipv6.conf.{self.ETH_DEV}.accept_ra=2') 572*cfb92d14SAndroid Build Coastguard Worker self.bash(f'sysctl net.ipv6.conf.{self.ETH_DEV}.accept_ra_rt_info_max_plen=64') 573*cfb92d14SAndroid Build Coastguard Worker 574*cfb92d14SAndroid Build Coastguard Worker 575*cfb92d14SAndroid Build Coastguard Workerclass OtCli: 576*cfb92d14SAndroid Build Coastguard Worker RESET_DELAY = 0.1 577*cfb92d14SAndroid Build Coastguard Worker 578*cfb92d14SAndroid Build Coastguard Worker def __init__(self, nodeid, is_mtd=False, version=None, is_bbr=False, **kwargs): 579*cfb92d14SAndroid Build Coastguard Worker self.verbose = int(float(os.getenv('VERBOSE', 0))) 580*cfb92d14SAndroid Build Coastguard Worker self.node_type = os.getenv('NODE_TYPE', 'sim') 581*cfb92d14SAndroid Build Coastguard Worker self.env_version = os.getenv('THREAD_VERSION', '1.1') 582*cfb92d14SAndroid Build Coastguard Worker self.is_bbr = is_bbr 583*cfb92d14SAndroid Build Coastguard Worker self._initialized = False 584*cfb92d14SAndroid Build Coastguard Worker if os.getenv('COVERAGE', 0) and os.getenv('CC', 'gcc') == 'gcc': 585*cfb92d14SAndroid Build Coastguard Worker self._cmd_prefix = '/usr/bin/env GCOV_PREFIX=%s/ot-run/%s/ot-gcda.%d ' % (os.getenv( 586*cfb92d14SAndroid Build Coastguard Worker 'top_srcdir', '.'), sys.argv[0], nodeid) 587*cfb92d14SAndroid Build Coastguard Worker else: 588*cfb92d14SAndroid Build Coastguard Worker self._cmd_prefix = '' 589*cfb92d14SAndroid Build Coastguard Worker 590*cfb92d14SAndroid Build Coastguard Worker if version is not None: 591*cfb92d14SAndroid Build Coastguard Worker self.version = version 592*cfb92d14SAndroid Build Coastguard Worker else: 593*cfb92d14SAndroid Build Coastguard Worker self.version = self.env_version 594*cfb92d14SAndroid Build Coastguard Worker 595*cfb92d14SAndroid Build Coastguard Worker mode = os.environ.get('USE_MTD') == '1' and is_mtd and 'mtd' or 'ftd' 596*cfb92d14SAndroid Build Coastguard Worker 597*cfb92d14SAndroid Build Coastguard Worker if self.node_type == 'soc': 598*cfb92d14SAndroid Build Coastguard Worker self.__init_soc(nodeid) 599*cfb92d14SAndroid Build Coastguard Worker elif self.node_type == 'ncp-sim': 600*cfb92d14SAndroid Build Coastguard Worker # TODO use mode after ncp-mtd is available. 601*cfb92d14SAndroid Build Coastguard Worker self.__init_ncp_sim(nodeid, 'ftd') 602*cfb92d14SAndroid Build Coastguard Worker else: 603*cfb92d14SAndroid Build Coastguard Worker self.__init_sim(nodeid, mode) 604*cfb92d14SAndroid Build Coastguard Worker 605*cfb92d14SAndroid Build Coastguard Worker if self.verbose: 606*cfb92d14SAndroid Build Coastguard Worker self.pexpect.logfile_read = sys.stdout.buffer 607*cfb92d14SAndroid Build Coastguard Worker 608*cfb92d14SAndroid Build Coastguard Worker self._initialized = True 609*cfb92d14SAndroid Build Coastguard Worker 610*cfb92d14SAndroid Build Coastguard Worker def __init_sim(self, nodeid, mode): 611*cfb92d14SAndroid Build Coastguard Worker """ Initialize a simulation node. """ 612*cfb92d14SAndroid Build Coastguard Worker 613*cfb92d14SAndroid Build Coastguard Worker # Default command if no match below, will be overridden if below conditions are met. 614*cfb92d14SAndroid Build Coastguard Worker cmd = './ot-cli-%s' % (mode) 615*cfb92d14SAndroid Build Coastguard Worker 616*cfb92d14SAndroid Build Coastguard Worker # For Thread 1.2 MTD node, use ot-cli-mtd build regardless of OT_CLI_PATH 617*cfb92d14SAndroid Build Coastguard Worker if self.version != '1.1' and mode == 'mtd' and 'top_builddir' in os.environ: 618*cfb92d14SAndroid Build Coastguard Worker srcdir = os.environ['top_builddir'] 619*cfb92d14SAndroid Build Coastguard Worker cmd = '%s/examples/apps/cli/ot-cli-%s %d' % (srcdir, mode, nodeid) 620*cfb92d14SAndroid Build Coastguard Worker 621*cfb92d14SAndroid Build Coastguard Worker # If Thread version of node matches the testing environment version. 622*cfb92d14SAndroid Build Coastguard Worker elif self.version == self.env_version: 623*cfb92d14SAndroid Build Coastguard Worker # Load Thread 1.2 BBR device when testing Thread 1.2 scenarios 624*cfb92d14SAndroid Build Coastguard Worker # which requires device with Backbone functionality. 625*cfb92d14SAndroid Build Coastguard Worker if self.version != '1.1' and self.is_bbr: 626*cfb92d14SAndroid Build Coastguard Worker if 'OT_CLI_PATH_BBR' in os.environ: 627*cfb92d14SAndroid Build Coastguard Worker cmd = os.environ['OT_CLI_PATH_BBR'] 628*cfb92d14SAndroid Build Coastguard Worker elif 'top_builddir_1_3_bbr' in os.environ: 629*cfb92d14SAndroid Build Coastguard Worker srcdir = os.environ['top_builddir_1_3_bbr'] 630*cfb92d14SAndroid Build Coastguard Worker cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode) 631*cfb92d14SAndroid Build Coastguard Worker 632*cfb92d14SAndroid Build Coastguard Worker # Load Thread device of the testing environment version (may be 1.1 or 1.2) 633*cfb92d14SAndroid Build Coastguard Worker else: 634*cfb92d14SAndroid Build Coastguard Worker if 'OT_CLI_PATH' in os.environ: 635*cfb92d14SAndroid Build Coastguard Worker cmd = os.environ['OT_CLI_PATH'] 636*cfb92d14SAndroid Build Coastguard Worker elif 'top_builddir' in os.environ: 637*cfb92d14SAndroid Build Coastguard Worker srcdir = os.environ['top_builddir'] 638*cfb92d14SAndroid Build Coastguard Worker cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode) 639*cfb92d14SAndroid Build Coastguard Worker 640*cfb92d14SAndroid Build Coastguard Worker if 'RADIO_DEVICE' in os.environ: 641*cfb92d14SAndroid Build Coastguard Worker cmd += ' --real-time-signal=+1 -v spinel+hdlc+uart://%s?forkpty-arg=%d' % (os.environ['RADIO_DEVICE'], 642*cfb92d14SAndroid Build Coastguard Worker nodeid) 643*cfb92d14SAndroid Build Coastguard Worker self.is_posix = True 644*cfb92d14SAndroid Build Coastguard Worker else: 645*cfb92d14SAndroid Build Coastguard Worker cmd += ' %d' % nodeid 646*cfb92d14SAndroid Build Coastguard Worker 647*cfb92d14SAndroid Build Coastguard Worker # Load Thread 1.1 node when testing Thread 1.2 scenarios for interoperability 648*cfb92d14SAndroid Build Coastguard Worker elif self.version == '1.1': 649*cfb92d14SAndroid Build Coastguard Worker # Posix app 650*cfb92d14SAndroid Build Coastguard Worker if 'OT_CLI_PATH_1_1' in os.environ: 651*cfb92d14SAndroid Build Coastguard Worker cmd = os.environ['OT_CLI_PATH_1_1'] 652*cfb92d14SAndroid Build Coastguard Worker elif 'top_builddir_1_1' in os.environ: 653*cfb92d14SAndroid Build Coastguard Worker srcdir = os.environ['top_builddir_1_1'] 654*cfb92d14SAndroid Build Coastguard Worker cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode) 655*cfb92d14SAndroid Build Coastguard Worker 656*cfb92d14SAndroid Build Coastguard Worker if 'RADIO_DEVICE_1_1' in os.environ: 657*cfb92d14SAndroid Build Coastguard Worker cmd += ' --real-time-signal=+1 -v spinel+hdlc+uart://%s?forkpty-arg=%d' % ( 658*cfb92d14SAndroid Build Coastguard Worker os.environ['RADIO_DEVICE_1_1'], nodeid) 659*cfb92d14SAndroid Build Coastguard Worker self.is_posix = True 660*cfb92d14SAndroid Build Coastguard Worker else: 661*cfb92d14SAndroid Build Coastguard Worker cmd += ' %d' % nodeid 662*cfb92d14SAndroid Build Coastguard Worker 663*cfb92d14SAndroid Build Coastguard Worker print("%s" % cmd) 664*cfb92d14SAndroid Build Coastguard Worker 665*cfb92d14SAndroid Build Coastguard Worker self.pexpect = pexpect.popen_spawn.PopenSpawn(self._cmd_prefix + cmd, timeout=10) 666*cfb92d14SAndroid Build Coastguard Worker 667*cfb92d14SAndroid Build Coastguard Worker # Add delay to ensure that the process is ready to receive commands. 668*cfb92d14SAndroid Build Coastguard Worker timeout = 0.4 669*cfb92d14SAndroid Build Coastguard Worker while timeout > 0: 670*cfb92d14SAndroid Build Coastguard Worker self.pexpect.send('\r\n') 671*cfb92d14SAndroid Build Coastguard Worker try: 672*cfb92d14SAndroid Build Coastguard Worker self.pexpect.expect('> ', timeout=0.1) 673*cfb92d14SAndroid Build Coastguard Worker break 674*cfb92d14SAndroid Build Coastguard Worker except pexpect.TIMEOUT: 675*cfb92d14SAndroid Build Coastguard Worker timeout -= 0.1 676*cfb92d14SAndroid Build Coastguard Worker 677*cfb92d14SAndroid Build Coastguard Worker def __init_ncp_sim(self, nodeid, mode): 678*cfb92d14SAndroid Build Coastguard Worker """ Initialize an NCP simulation node. """ 679*cfb92d14SAndroid Build Coastguard Worker 680*cfb92d14SAndroid Build Coastguard Worker # Default command if no match below, will be overridden if below conditions are met. 681*cfb92d14SAndroid Build Coastguard Worker cmd = 'spinel-cli.py -p ./ot-ncp-%s -n' % mode 682*cfb92d14SAndroid Build Coastguard Worker 683*cfb92d14SAndroid Build Coastguard Worker # If Thread version of node matches the testing environment version. 684*cfb92d14SAndroid Build Coastguard Worker if self.version == self.env_version: 685*cfb92d14SAndroid Build Coastguard Worker if 'RADIO_DEVICE' in os.environ: 686*cfb92d14SAndroid Build Coastguard Worker args = ' --real-time-signal=+1 spinel+hdlc+uart://%s?forkpty-arg=%d' % (os.environ['RADIO_DEVICE'], 687*cfb92d14SAndroid Build Coastguard Worker nodeid) 688*cfb92d14SAndroid Build Coastguard Worker self.is_posix = True 689*cfb92d14SAndroid Build Coastguard Worker else: 690*cfb92d14SAndroid Build Coastguard Worker args = '' 691*cfb92d14SAndroid Build Coastguard Worker 692*cfb92d14SAndroid Build Coastguard Worker # Load Thread 1.2 BBR device when testing Thread 1.2 scenarios 693*cfb92d14SAndroid Build Coastguard Worker # which requires device with Backbone functionality. 694*cfb92d14SAndroid Build Coastguard Worker if self.version != '1.1' and self.is_bbr: 695*cfb92d14SAndroid Build Coastguard Worker if 'OT_NCP_PATH_1_3_BBR' in os.environ: 696*cfb92d14SAndroid Build Coastguard Worker cmd = 'spinel-cli.py -p "%s%s" -n' % ( 697*cfb92d14SAndroid Build Coastguard Worker os.environ['OT_NCP_PATH_1_3_BBR'], 698*cfb92d14SAndroid Build Coastguard Worker args, 699*cfb92d14SAndroid Build Coastguard Worker ) 700*cfb92d14SAndroid Build Coastguard Worker elif 'top_builddir_1_3_bbr' in os.environ: 701*cfb92d14SAndroid Build Coastguard Worker srcdir = os.environ['top_builddir_1_3_bbr'] 702*cfb92d14SAndroid Build Coastguard Worker cmd = '%s/examples/apps/ncp/ot-ncp-%s' % (srcdir, mode) 703*cfb92d14SAndroid Build Coastguard Worker cmd = 'spinel-cli.py -p "%s%s" -n' % ( 704*cfb92d14SAndroid Build Coastguard Worker cmd, 705*cfb92d14SAndroid Build Coastguard Worker args, 706*cfb92d14SAndroid Build Coastguard Worker ) 707*cfb92d14SAndroid Build Coastguard Worker 708*cfb92d14SAndroid Build Coastguard Worker # Load Thread device of the testing environment version (may be 1.1 or 1.2). 709*cfb92d14SAndroid Build Coastguard Worker else: 710*cfb92d14SAndroid Build Coastguard Worker if 'OT_NCP_PATH' in os.environ: 711*cfb92d14SAndroid Build Coastguard Worker cmd = 'spinel-cli.py -p "%s%s" -n' % ( 712*cfb92d14SAndroid Build Coastguard Worker os.environ['OT_NCP_PATH'], 713*cfb92d14SAndroid Build Coastguard Worker args, 714*cfb92d14SAndroid Build Coastguard Worker ) 715*cfb92d14SAndroid Build Coastguard Worker elif 'top_builddir' in os.environ: 716*cfb92d14SAndroid Build Coastguard Worker srcdir = os.environ['top_builddir'] 717*cfb92d14SAndroid Build Coastguard Worker cmd = '%s/examples/apps/ncp/ot-ncp-%s' % (srcdir, mode) 718*cfb92d14SAndroid Build Coastguard Worker cmd = 'spinel-cli.py -p "%s%s" -n' % ( 719*cfb92d14SAndroid Build Coastguard Worker cmd, 720*cfb92d14SAndroid Build Coastguard Worker args, 721*cfb92d14SAndroid Build Coastguard Worker ) 722*cfb92d14SAndroid Build Coastguard Worker 723*cfb92d14SAndroid Build Coastguard Worker # Load Thread 1.1 node when testing Thread 1.2 scenarios for interoperability. 724*cfb92d14SAndroid Build Coastguard Worker elif self.version == '1.1': 725*cfb92d14SAndroid Build Coastguard Worker if 'RADIO_DEVICE_1_1' in os.environ: 726*cfb92d14SAndroid Build Coastguard Worker args = ' --real-time-signal=+1 spinel+hdlc+uart://%s?forkpty-arg=%d' % (os.environ['RADIO_DEVICE_1_1'], 727*cfb92d14SAndroid Build Coastguard Worker nodeid) 728*cfb92d14SAndroid Build Coastguard Worker self.is_posix = True 729*cfb92d14SAndroid Build Coastguard Worker else: 730*cfb92d14SAndroid Build Coastguard Worker args = '' 731*cfb92d14SAndroid Build Coastguard Worker 732*cfb92d14SAndroid Build Coastguard Worker if 'OT_NCP_PATH_1_1' in os.environ: 733*cfb92d14SAndroid Build Coastguard Worker cmd = 'spinel-cli.py -p "%s%s" -n' % ( 734*cfb92d14SAndroid Build Coastguard Worker os.environ['OT_NCP_PATH_1_1'], 735*cfb92d14SAndroid Build Coastguard Worker args, 736*cfb92d14SAndroid Build Coastguard Worker ) 737*cfb92d14SAndroid Build Coastguard Worker elif 'top_builddir_1_1' in os.environ: 738*cfb92d14SAndroid Build Coastguard Worker srcdir = os.environ['top_builddir_1_1'] 739*cfb92d14SAndroid Build Coastguard Worker cmd = '%s/examples/apps/ncp/ot-ncp-%s' % (srcdir, mode) 740*cfb92d14SAndroid Build Coastguard Worker cmd = 'spinel-cli.py -p "%s%s" -n' % ( 741*cfb92d14SAndroid Build Coastguard Worker cmd, 742*cfb92d14SAndroid Build Coastguard Worker args, 743*cfb92d14SAndroid Build Coastguard Worker ) 744*cfb92d14SAndroid Build Coastguard Worker 745*cfb92d14SAndroid Build Coastguard Worker cmd += ' %d' % nodeid 746*cfb92d14SAndroid Build Coastguard Worker print("%s" % cmd) 747*cfb92d14SAndroid Build Coastguard Worker 748*cfb92d14SAndroid Build Coastguard Worker self.pexpect = pexpect.spawn(self._cmd_prefix + cmd, timeout=10) 749*cfb92d14SAndroid Build Coastguard Worker 750*cfb92d14SAndroid Build Coastguard Worker # Add delay to ensure that the process is ready to receive commands. 751*cfb92d14SAndroid Build Coastguard Worker time.sleep(0.2) 752*cfb92d14SAndroid Build Coastguard Worker self._expect('spinel-cli >') 753*cfb92d14SAndroid Build Coastguard Worker self.debug(int(os.getenv('DEBUG', '0'))) 754*cfb92d14SAndroid Build Coastguard Worker 755*cfb92d14SAndroid Build Coastguard Worker def __init_soc(self, nodeid): 756*cfb92d14SAndroid Build Coastguard Worker """ Initialize a System-on-a-chip node connected via UART. """ 757*cfb92d14SAndroid Build Coastguard Worker import fdpexpect 758*cfb92d14SAndroid Build Coastguard Worker 759*cfb92d14SAndroid Build Coastguard Worker serialPort = '/dev/ttyUSB%d' % ((nodeid - 1) * 2) 760*cfb92d14SAndroid Build Coastguard Worker self.pexpect = fdpexpect.fdspawn(os.open(serialPort, os.O_RDWR | os.O_NONBLOCK | os.O_NOCTTY)) 761*cfb92d14SAndroid Build Coastguard Worker 762*cfb92d14SAndroid Build Coastguard Worker def destroy(self): 763*cfb92d14SAndroid Build Coastguard Worker if not self._initialized: 764*cfb92d14SAndroid Build Coastguard Worker return 765*cfb92d14SAndroid Build Coastguard Worker 766*cfb92d14SAndroid Build Coastguard Worker if (hasattr(self.pexpect, 'proc') and self.pexpect.proc.poll() is None or 767*cfb92d14SAndroid Build Coastguard Worker not hasattr(self.pexpect, 'proc') and self.pexpect.isalive()): 768*cfb92d14SAndroid Build Coastguard Worker print("%d: exit" % self.nodeid) 769*cfb92d14SAndroid Build Coastguard Worker self.pexpect.send('exit\n') 770*cfb92d14SAndroid Build Coastguard Worker self.pexpect.expect(pexpect.EOF) 771*cfb92d14SAndroid Build Coastguard Worker self.pexpect.wait() 772*cfb92d14SAndroid Build Coastguard Worker self._initialized = False 773*cfb92d14SAndroid Build Coastguard Worker 774*cfb92d14SAndroid Build Coastguard Worker 775*cfb92d14SAndroid Build Coastguard Workerclass NodeImpl: 776*cfb92d14SAndroid Build Coastguard Worker is_host = False 777*cfb92d14SAndroid Build Coastguard Worker is_otbr = False 778*cfb92d14SAndroid Build Coastguard Worker 779*cfb92d14SAndroid Build Coastguard Worker def __init__(self, nodeid, name=None, simulator=None, **kwargs): 780*cfb92d14SAndroid Build Coastguard Worker self.nodeid = nodeid 781*cfb92d14SAndroid Build Coastguard Worker self.name = name or ('Node%d' % nodeid) 782*cfb92d14SAndroid Build Coastguard Worker self.is_posix = False 783*cfb92d14SAndroid Build Coastguard Worker 784*cfb92d14SAndroid Build Coastguard Worker self.simulator = simulator 785*cfb92d14SAndroid Build Coastguard Worker if self.simulator: 786*cfb92d14SAndroid Build Coastguard Worker self.simulator.add_node(self) 787*cfb92d14SAndroid Build Coastguard Worker 788*cfb92d14SAndroid Build Coastguard Worker super().__init__(nodeid, **kwargs) 789*cfb92d14SAndroid Build Coastguard Worker 790*cfb92d14SAndroid Build Coastguard Worker self.set_addr64('%016x' % (thread_cert.EXTENDED_ADDRESS_BASE + nodeid)) 791*cfb92d14SAndroid Build Coastguard Worker 792*cfb92d14SAndroid Build Coastguard Worker def _expect(self, pattern, timeout=-1, *args, **kwargs): 793*cfb92d14SAndroid Build Coastguard Worker """ Process simulator events until expected the pattern. """ 794*cfb92d14SAndroid Build Coastguard Worker if timeout == -1: 795*cfb92d14SAndroid Build Coastguard Worker timeout = self.pexpect.timeout 796*cfb92d14SAndroid Build Coastguard Worker 797*cfb92d14SAndroid Build Coastguard Worker assert timeout > 0 798*cfb92d14SAndroid Build Coastguard Worker 799*cfb92d14SAndroid Build Coastguard Worker while timeout > 0: 800*cfb92d14SAndroid Build Coastguard Worker try: 801*cfb92d14SAndroid Build Coastguard Worker return self.pexpect.expect(pattern, 0.1, *args, **kwargs) 802*cfb92d14SAndroid Build Coastguard Worker except pexpect.TIMEOUT: 803*cfb92d14SAndroid Build Coastguard Worker timeout -= 0.1 804*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(0) 805*cfb92d14SAndroid Build Coastguard Worker if timeout <= 0: 806*cfb92d14SAndroid Build Coastguard Worker raise 807*cfb92d14SAndroid Build Coastguard Worker 808*cfb92d14SAndroid Build Coastguard Worker def _expect_done(self, timeout=-1): 809*cfb92d14SAndroid Build Coastguard Worker self._expect('Done', timeout) 810*cfb92d14SAndroid Build Coastguard Worker 811*cfb92d14SAndroid Build Coastguard Worker def _expect_result(self, pattern, *args, **kwargs): 812*cfb92d14SAndroid Build Coastguard Worker """Expect a single matching result. 813*cfb92d14SAndroid Build Coastguard Worker 814*cfb92d14SAndroid Build Coastguard Worker The arguments are identical to pexpect.expect(). 815*cfb92d14SAndroid Build Coastguard Worker 816*cfb92d14SAndroid Build Coastguard Worker Returns: 817*cfb92d14SAndroid Build Coastguard Worker The matched line. 818*cfb92d14SAndroid Build Coastguard Worker """ 819*cfb92d14SAndroid Build Coastguard Worker results = self._expect_results(pattern, *args, **kwargs) 820*cfb92d14SAndroid Build Coastguard Worker assert len(results) == 1, results 821*cfb92d14SAndroid Build Coastguard Worker return results[0] 822*cfb92d14SAndroid Build Coastguard Worker 823*cfb92d14SAndroid Build Coastguard Worker def _expect_results(self, pattern, *args, **kwargs): 824*cfb92d14SAndroid Build Coastguard Worker """Expect multiple matching results. 825*cfb92d14SAndroid Build Coastguard Worker 826*cfb92d14SAndroid Build Coastguard Worker The arguments are identical to pexpect.expect(). 827*cfb92d14SAndroid Build Coastguard Worker 828*cfb92d14SAndroid Build Coastguard Worker Returns: 829*cfb92d14SAndroid Build Coastguard Worker The matched lines. 830*cfb92d14SAndroid Build Coastguard Worker """ 831*cfb92d14SAndroid Build Coastguard Worker output = self._expect_command_output() 832*cfb92d14SAndroid Build Coastguard Worker results = [line for line in output if self._match_pattern(line, pattern)] 833*cfb92d14SAndroid Build Coastguard Worker return results 834*cfb92d14SAndroid Build Coastguard Worker 835*cfb92d14SAndroid Build Coastguard Worker def _expect_key_value_pairs(self, pattern, separator=': '): 836*cfb92d14SAndroid Build Coastguard Worker """Expect 'key: value' in multiple lines. 837*cfb92d14SAndroid Build Coastguard Worker 838*cfb92d14SAndroid Build Coastguard Worker Returns: 839*cfb92d14SAndroid Build Coastguard Worker Dictionary of the key:value pairs. 840*cfb92d14SAndroid Build Coastguard Worker """ 841*cfb92d14SAndroid Build Coastguard Worker result = {} 842*cfb92d14SAndroid Build Coastguard Worker for line in self._expect_results(pattern): 843*cfb92d14SAndroid Build Coastguard Worker key, val = line.split(separator) 844*cfb92d14SAndroid Build Coastguard Worker result.update({key: val}) 845*cfb92d14SAndroid Build Coastguard Worker return result 846*cfb92d14SAndroid Build Coastguard Worker 847*cfb92d14SAndroid Build Coastguard Worker @staticmethod 848*cfb92d14SAndroid Build Coastguard Worker def _match_pattern(line, pattern): 849*cfb92d14SAndroid Build Coastguard Worker if isinstance(pattern, str): 850*cfb92d14SAndroid Build Coastguard Worker pattern = re.compile(pattern) 851*cfb92d14SAndroid Build Coastguard Worker 852*cfb92d14SAndroid Build Coastguard Worker if isinstance(pattern, typing.Pattern): 853*cfb92d14SAndroid Build Coastguard Worker return pattern.match(line) 854*cfb92d14SAndroid Build Coastguard Worker else: 855*cfb92d14SAndroid Build Coastguard Worker return any(NodeImpl._match_pattern(line, p) for p in pattern) 856*cfb92d14SAndroid Build Coastguard Worker 857*cfb92d14SAndroid Build Coastguard Worker def _expect_command_output(self, ignore_logs=True): 858*cfb92d14SAndroid Build Coastguard Worker lines = [] 859*cfb92d14SAndroid Build Coastguard Worker 860*cfb92d14SAndroid Build Coastguard Worker while True: 861*cfb92d14SAndroid Build Coastguard Worker line = self.__readline(ignore_logs=ignore_logs) 862*cfb92d14SAndroid Build Coastguard Worker 863*cfb92d14SAndroid Build Coastguard Worker if line == 'Done': 864*cfb92d14SAndroid Build Coastguard Worker break 865*cfb92d14SAndroid Build Coastguard Worker elif line.startswith('Error '): 866*cfb92d14SAndroid Build Coastguard Worker raise Exception(line) 867*cfb92d14SAndroid Build Coastguard Worker else: 868*cfb92d14SAndroid Build Coastguard Worker lines.append(line) 869*cfb92d14SAndroid Build Coastguard Worker 870*cfb92d14SAndroid Build Coastguard Worker print(f'_expect_command_output() returns {lines!r}') 871*cfb92d14SAndroid Build Coastguard Worker return lines 872*cfb92d14SAndroid Build Coastguard Worker 873*cfb92d14SAndroid Build Coastguard Worker def __is_logging_line(self, line: str) -> bool: 874*cfb92d14SAndroid Build Coastguard Worker return len(line) >= 3 and line[:3] in {'[D]', '[I]', '[N]', '[W]', '[C]', '[-]'} 875*cfb92d14SAndroid Build Coastguard Worker 876*cfb92d14SAndroid Build Coastguard Worker def read_cert_messages_in_commissioning_log(self, timeout=-1): 877*cfb92d14SAndroid Build Coastguard Worker """Get the log of the traffic after DTLS handshake. 878*cfb92d14SAndroid Build Coastguard Worker """ 879*cfb92d14SAndroid Build Coastguard Worker format_str = br"=+?\[\[THCI\].*?type=%s.*?\].*?=+?[\s\S]+?-{40,}" 880*cfb92d14SAndroid Build Coastguard Worker join_fin_req = format_str % br"JOIN_FIN\.req" 881*cfb92d14SAndroid Build Coastguard Worker join_fin_rsp = format_str % br"JOIN_FIN\.rsp" 882*cfb92d14SAndroid Build Coastguard Worker dummy_format_str = br"\[THCI\].*?type=%s.*?" 883*cfb92d14SAndroid Build Coastguard Worker join_ent_ntf = dummy_format_str % br"JOIN_ENT\.ntf" 884*cfb92d14SAndroid Build Coastguard Worker join_ent_rsp = dummy_format_str % br"JOIN_ENT\.rsp" 885*cfb92d14SAndroid Build Coastguard Worker pattern = (b"(" + join_fin_req + b")|(" + join_fin_rsp + b")|(" + join_ent_ntf + b")|(" + join_ent_rsp + b")") 886*cfb92d14SAndroid Build Coastguard Worker 887*cfb92d14SAndroid Build Coastguard Worker messages = [] 888*cfb92d14SAndroid Build Coastguard Worker # There are at most 4 cert messages both for joiner and commissioner 889*cfb92d14SAndroid Build Coastguard Worker for _ in range(0, 4): 890*cfb92d14SAndroid Build Coastguard Worker try: 891*cfb92d14SAndroid Build Coastguard Worker self._expect(pattern, timeout=timeout) 892*cfb92d14SAndroid Build Coastguard Worker log = self.pexpect.match.group(0) 893*cfb92d14SAndroid Build Coastguard Worker messages.append(self._extract_cert_message(log)) 894*cfb92d14SAndroid Build Coastguard Worker except BaseException: 895*cfb92d14SAndroid Build Coastguard Worker break 896*cfb92d14SAndroid Build Coastguard Worker return messages 897*cfb92d14SAndroid Build Coastguard Worker 898*cfb92d14SAndroid Build Coastguard Worker def _extract_cert_message(self, log): 899*cfb92d14SAndroid Build Coastguard Worker res = re.search(br"direction=\w+", log) 900*cfb92d14SAndroid Build Coastguard Worker assert res 901*cfb92d14SAndroid Build Coastguard Worker direction = res.group(0).split(b'=')[1].strip() 902*cfb92d14SAndroid Build Coastguard Worker 903*cfb92d14SAndroid Build Coastguard Worker res = re.search(br"type=\S+", log) 904*cfb92d14SAndroid Build Coastguard Worker assert res 905*cfb92d14SAndroid Build Coastguard Worker type = res.group(0).split(b'=')[1].strip() 906*cfb92d14SAndroid Build Coastguard Worker 907*cfb92d14SAndroid Build Coastguard Worker payload = bytearray([]) 908*cfb92d14SAndroid Build Coastguard Worker payload_len = 0 909*cfb92d14SAndroid Build Coastguard Worker if type in [b"JOIN_FIN.req", b"JOIN_FIN.rsp"]: 910*cfb92d14SAndroid Build Coastguard Worker res = re.search(br"len=\d+", log) 911*cfb92d14SAndroid Build Coastguard Worker assert res 912*cfb92d14SAndroid Build Coastguard Worker payload_len = int(res.group(0).split(b'=')[1].strip()) 913*cfb92d14SAndroid Build Coastguard Worker 914*cfb92d14SAndroid Build Coastguard Worker hex_pattern = br"\|(\s([0-9a-fA-F]{2}|\.\.))+?\s+?\|" 915*cfb92d14SAndroid Build Coastguard Worker while True: 916*cfb92d14SAndroid Build Coastguard Worker res = re.search(hex_pattern, log) 917*cfb92d14SAndroid Build Coastguard Worker if not res: 918*cfb92d14SAndroid Build Coastguard Worker break 919*cfb92d14SAndroid Build Coastguard Worker data = [int(hex, 16) for hex in res.group(0)[1:-1].split(b' ') if hex and hex != b'..'] 920*cfb92d14SAndroid Build Coastguard Worker payload += bytearray(data) 921*cfb92d14SAndroid Build Coastguard Worker log = log[res.end() - 1:] 922*cfb92d14SAndroid Build Coastguard Worker assert len(payload) == payload_len 923*cfb92d14SAndroid Build Coastguard Worker return (direction, type, payload) 924*cfb92d14SAndroid Build Coastguard Worker 925*cfb92d14SAndroid Build Coastguard Worker def send_command(self, cmd, go=True, expect_command_echo=True): 926*cfb92d14SAndroid Build Coastguard Worker print("%d: %s" % (self.nodeid, cmd)) 927*cfb92d14SAndroid Build Coastguard Worker self.pexpect.send(cmd + '\n') 928*cfb92d14SAndroid Build Coastguard Worker if go: 929*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(0, nodeid=self.nodeid) 930*cfb92d14SAndroid Build Coastguard Worker sys.stdout.flush() 931*cfb92d14SAndroid Build Coastguard Worker 932*cfb92d14SAndroid Build Coastguard Worker if expect_command_echo: 933*cfb92d14SAndroid Build Coastguard Worker self._expect_command_echo(cmd) 934*cfb92d14SAndroid Build Coastguard Worker 935*cfb92d14SAndroid Build Coastguard Worker def _expect_command_echo(self, cmd): 936*cfb92d14SAndroid Build Coastguard Worker cmd = cmd.strip() 937*cfb92d14SAndroid Build Coastguard Worker while True: 938*cfb92d14SAndroid Build Coastguard Worker line = self.__readline() 939*cfb92d14SAndroid Build Coastguard Worker if line == cmd: 940*cfb92d14SAndroid Build Coastguard Worker break 941*cfb92d14SAndroid Build Coastguard Worker 942*cfb92d14SAndroid Build Coastguard Worker logging.warning("expecting echo %r, but read %r", cmd, line) 943*cfb92d14SAndroid Build Coastguard Worker 944*cfb92d14SAndroid Build Coastguard Worker def __readline(self, ignore_logs=True): 945*cfb92d14SAndroid Build Coastguard Worker PROMPT = 'spinel-cli > ' if self.node_type == 'ncp-sim' else '> ' 946*cfb92d14SAndroid Build Coastguard Worker while True: 947*cfb92d14SAndroid Build Coastguard Worker self._expect(r"[^\n]+\n") 948*cfb92d14SAndroid Build Coastguard Worker line = self.pexpect.match.group(0).decode('utf8').strip() 949*cfb92d14SAndroid Build Coastguard Worker while line.startswith(PROMPT): 950*cfb92d14SAndroid Build Coastguard Worker line = line[len(PROMPT):] 951*cfb92d14SAndroid Build Coastguard Worker 952*cfb92d14SAndroid Build Coastguard Worker if line == '': 953*cfb92d14SAndroid Build Coastguard Worker continue 954*cfb92d14SAndroid Build Coastguard Worker 955*cfb92d14SAndroid Build Coastguard Worker if ignore_logs and self.__is_logging_line(line): 956*cfb92d14SAndroid Build Coastguard Worker continue 957*cfb92d14SAndroid Build Coastguard Worker 958*cfb92d14SAndroid Build Coastguard Worker return line 959*cfb92d14SAndroid Build Coastguard Worker 960*cfb92d14SAndroid Build Coastguard Worker def get_commands(self): 961*cfb92d14SAndroid Build Coastguard Worker self.send_command('?') 962*cfb92d14SAndroid Build Coastguard Worker self._expect('Commands:') 963*cfb92d14SAndroid Build Coastguard Worker return self._expect_results(r'\S+') 964*cfb92d14SAndroid Build Coastguard Worker 965*cfb92d14SAndroid Build Coastguard Worker def set_mode(self, mode): 966*cfb92d14SAndroid Build Coastguard Worker cmd = 'mode %s' % mode 967*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 968*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 969*cfb92d14SAndroid Build Coastguard Worker 970*cfb92d14SAndroid Build Coastguard Worker def debug(self, level): 971*cfb92d14SAndroid Build Coastguard Worker # `debug` command will not trigger interaction with simulator 972*cfb92d14SAndroid Build Coastguard Worker self.send_command('debug %d' % level, go=False) 973*cfb92d14SAndroid Build Coastguard Worker 974*cfb92d14SAndroid Build Coastguard Worker def start(self): 975*cfb92d14SAndroid Build Coastguard Worker self.interface_up() 976*cfb92d14SAndroid Build Coastguard Worker self.thread_start() 977*cfb92d14SAndroid Build Coastguard Worker 978*cfb92d14SAndroid Build Coastguard Worker def stop(self): 979*cfb92d14SAndroid Build Coastguard Worker self.thread_stop() 980*cfb92d14SAndroid Build Coastguard Worker self.interface_down() 981*cfb92d14SAndroid Build Coastguard Worker 982*cfb92d14SAndroid Build Coastguard Worker def set_log_level(self, level: int): 983*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'log level {level}') 984*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 985*cfb92d14SAndroid Build Coastguard Worker 986*cfb92d14SAndroid Build Coastguard Worker def interface_up(self): 987*cfb92d14SAndroid Build Coastguard Worker self.send_command('ifconfig up') 988*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 989*cfb92d14SAndroid Build Coastguard Worker 990*cfb92d14SAndroid Build Coastguard Worker def interface_down(self): 991*cfb92d14SAndroid Build Coastguard Worker self.send_command('ifconfig down') 992*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 993*cfb92d14SAndroid Build Coastguard Worker 994*cfb92d14SAndroid Build Coastguard Worker def thread_start(self): 995*cfb92d14SAndroid Build Coastguard Worker self.send_command('thread start') 996*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 997*cfb92d14SAndroid Build Coastguard Worker 998*cfb92d14SAndroid Build Coastguard Worker def thread_stop(self): 999*cfb92d14SAndroid Build Coastguard Worker self.send_command('thread stop') 1000*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1001*cfb92d14SAndroid Build Coastguard Worker 1002*cfb92d14SAndroid Build Coastguard Worker def detach(self, is_async=False): 1003*cfb92d14SAndroid Build Coastguard Worker cmd = 'detach' 1004*cfb92d14SAndroid Build Coastguard Worker if is_async: 1005*cfb92d14SAndroid Build Coastguard Worker cmd += ' async' 1006*cfb92d14SAndroid Build Coastguard Worker 1007*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1008*cfb92d14SAndroid Build Coastguard Worker 1009*cfb92d14SAndroid Build Coastguard Worker if is_async: 1010*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1011*cfb92d14SAndroid Build Coastguard Worker return 1012*cfb92d14SAndroid Build Coastguard Worker 1013*cfb92d14SAndroid Build Coastguard Worker end = self.simulator.now() + 4 1014*cfb92d14SAndroid Build Coastguard Worker while True: 1015*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(1) 1016*cfb92d14SAndroid Build Coastguard Worker try: 1017*cfb92d14SAndroid Build Coastguard Worker self._expect_done(timeout=0.1) 1018*cfb92d14SAndroid Build Coastguard Worker return 1019*cfb92d14SAndroid Build Coastguard Worker except (pexpect.TIMEOUT, socket.timeout): 1020*cfb92d14SAndroid Build Coastguard Worker if self.simulator.now() > end: 1021*cfb92d14SAndroid Build Coastguard Worker raise 1022*cfb92d14SAndroid Build Coastguard Worker 1023*cfb92d14SAndroid Build Coastguard Worker def expect_finished_detaching(self): 1024*cfb92d14SAndroid Build Coastguard Worker self._expect('Finished detaching') 1025*cfb92d14SAndroid Build Coastguard Worker 1026*cfb92d14SAndroid Build Coastguard Worker def commissioner_start(self): 1027*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner start' 1028*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1029*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1030*cfb92d14SAndroid Build Coastguard Worker 1031*cfb92d14SAndroid Build Coastguard Worker def commissioner_stop(self): 1032*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner stop' 1033*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1034*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1035*cfb92d14SAndroid Build Coastguard Worker 1036*cfb92d14SAndroid Build Coastguard Worker def commissioner_state(self): 1037*cfb92d14SAndroid Build Coastguard Worker states = [r'disabled', r'petitioning', r'active'] 1038*cfb92d14SAndroid Build Coastguard Worker self.send_command('commissioner state') 1039*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(states) 1040*cfb92d14SAndroid Build Coastguard Worker 1041*cfb92d14SAndroid Build Coastguard Worker def commissioner_add_joiner(self, addr, psk): 1042*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner joiner add %s %s' % (addr, psk) 1043*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1044*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1045*cfb92d14SAndroid Build Coastguard Worker 1046*cfb92d14SAndroid Build Coastguard Worker def commissioner_set_provisioning_url(self, provisioning_url=''): 1047*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner provisioningurl %s' % provisioning_url 1048*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1049*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1050*cfb92d14SAndroid Build Coastguard Worker 1051*cfb92d14SAndroid Build Coastguard Worker def joiner_start(self, pskd='', provisioning_url=''): 1052*cfb92d14SAndroid Build Coastguard Worker cmd = 'joiner start %s %s' % (pskd, provisioning_url) 1053*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1054*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1055*cfb92d14SAndroid Build Coastguard Worker 1056*cfb92d14SAndroid Build Coastguard Worker def clear_allowlist(self): 1057*cfb92d14SAndroid Build Coastguard Worker cmd = 'macfilter addr clear' 1058*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1059*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1060*cfb92d14SAndroid Build Coastguard Worker 1061*cfb92d14SAndroid Build Coastguard Worker def enable_allowlist(self): 1062*cfb92d14SAndroid Build Coastguard Worker cmd = 'macfilter addr allowlist' 1063*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1064*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1065*cfb92d14SAndroid Build Coastguard Worker 1066*cfb92d14SAndroid Build Coastguard Worker def disable_allowlist(self): 1067*cfb92d14SAndroid Build Coastguard Worker cmd = 'macfilter addr disable' 1068*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1069*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1070*cfb92d14SAndroid Build Coastguard Worker 1071*cfb92d14SAndroid Build Coastguard Worker def add_allowlist(self, addr, rssi=None): 1072*cfb92d14SAndroid Build Coastguard Worker cmd = 'macfilter addr add %s' % addr 1073*cfb92d14SAndroid Build Coastguard Worker 1074*cfb92d14SAndroid Build Coastguard Worker if rssi is not None: 1075*cfb92d14SAndroid Build Coastguard Worker cmd += ' %s' % rssi 1076*cfb92d14SAndroid Build Coastguard Worker 1077*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1078*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1079*cfb92d14SAndroid Build Coastguard Worker 1080*cfb92d14SAndroid Build Coastguard Worker def radiofilter_is_enabled(self) -> bool: 1081*cfb92d14SAndroid Build Coastguard Worker states = [r'Disabled', r'Enabled'] 1082*cfb92d14SAndroid Build Coastguard Worker self.send_command('radiofilter') 1083*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(states) == 'Enabled' 1084*cfb92d14SAndroid Build Coastguard Worker 1085*cfb92d14SAndroid Build Coastguard Worker def radiofilter_enable(self): 1086*cfb92d14SAndroid Build Coastguard Worker cmd = 'radiofilter enable' 1087*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1088*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1089*cfb92d14SAndroid Build Coastguard Worker 1090*cfb92d14SAndroid Build Coastguard Worker def radiofilter_disable(self): 1091*cfb92d14SAndroid Build Coastguard Worker cmd = 'radiofilter disable' 1092*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1093*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1094*cfb92d14SAndroid Build Coastguard Worker 1095*cfb92d14SAndroid Build Coastguard Worker def get_bbr_registration_jitter(self): 1096*cfb92d14SAndroid Build Coastguard Worker self.send_command('bbr jitter') 1097*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_result(r'\d+')) 1098*cfb92d14SAndroid Build Coastguard Worker 1099*cfb92d14SAndroid Build Coastguard Worker def set_bbr_registration_jitter(self, jitter): 1100*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr jitter %d' % jitter 1101*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1102*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1103*cfb92d14SAndroid Build Coastguard Worker 1104*cfb92d14SAndroid Build Coastguard Worker def get_rcp_version(self) -> str: 1105*cfb92d14SAndroid Build Coastguard Worker self.send_command('rcp version') 1106*cfb92d14SAndroid Build Coastguard Worker rcp_version = self._expect_command_output()[0].strip() 1107*cfb92d14SAndroid Build Coastguard Worker return rcp_version 1108*cfb92d14SAndroid Build Coastguard Worker 1109*cfb92d14SAndroid Build Coastguard Worker def srp_server_get_state(self): 1110*cfb92d14SAndroid Build Coastguard Worker states = ['disabled', 'running', 'stopped'] 1111*cfb92d14SAndroid Build Coastguard Worker self.send_command('srp server state') 1112*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(states) 1113*cfb92d14SAndroid Build Coastguard Worker 1114*cfb92d14SAndroid Build Coastguard Worker def srp_server_get_addr_mode(self): 1115*cfb92d14SAndroid Build Coastguard Worker modes = [r'unicast', r'anycast'] 1116*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp server addrmode') 1117*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(modes) 1118*cfb92d14SAndroid Build Coastguard Worker 1119*cfb92d14SAndroid Build Coastguard Worker def srp_server_set_addr_mode(self, mode): 1120*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp server addrmode {mode}') 1121*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1122*cfb92d14SAndroid Build Coastguard Worker 1123*cfb92d14SAndroid Build Coastguard Worker def srp_server_get_anycast_seq_num(self): 1124*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp server seqnum') 1125*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_result(r'\d+')) 1126*cfb92d14SAndroid Build Coastguard Worker 1127*cfb92d14SAndroid Build Coastguard Worker def srp_server_set_anycast_seq_num(self, seqnum): 1128*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp server seqnum {seqnum}') 1129*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1130*cfb92d14SAndroid Build Coastguard Worker 1131*cfb92d14SAndroid Build Coastguard Worker def srp_server_set_enabled(self, enable): 1132*cfb92d14SAndroid Build Coastguard Worker cmd = f'srp server {"enable" if enable else "disable"}' 1133*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1134*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1135*cfb92d14SAndroid Build Coastguard Worker 1136*cfb92d14SAndroid Build Coastguard Worker def srp_server_set_lease_range(self, min_lease, max_lease, min_key_lease, max_key_lease): 1137*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp server lease {min_lease} {max_lease} {min_key_lease} {max_key_lease}') 1138*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1139*cfb92d14SAndroid Build Coastguard Worker 1140*cfb92d14SAndroid Build Coastguard Worker def srp_server_set_ttl_range(self, min_ttl, max_ttl): 1141*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp server ttl {min_ttl} {max_ttl}') 1142*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1143*cfb92d14SAndroid Build Coastguard Worker 1144*cfb92d14SAndroid Build Coastguard Worker def srp_server_get_hosts(self): 1145*cfb92d14SAndroid Build Coastguard Worker """Returns the host list on the SRP server as a list of property 1146*cfb92d14SAndroid Build Coastguard Worker dictionary. 1147*cfb92d14SAndroid Build Coastguard Worker 1148*cfb92d14SAndroid Build Coastguard Worker Example output: 1149*cfb92d14SAndroid Build Coastguard Worker [{ 1150*cfb92d14SAndroid Build Coastguard Worker 'fullname': 'my-host.default.service.arpa.', 1151*cfb92d14SAndroid Build Coastguard Worker 'name': 'my-host', 1152*cfb92d14SAndroid Build Coastguard Worker 'deleted': 'false', 1153*cfb92d14SAndroid Build Coastguard Worker 'addresses': ['2001::1', '2001::2'] 1154*cfb92d14SAndroid Build Coastguard Worker }] 1155*cfb92d14SAndroid Build Coastguard Worker """ 1156*cfb92d14SAndroid Build Coastguard Worker 1157*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp server host' 1158*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1159*cfb92d14SAndroid Build Coastguard Worker lines = self._expect_command_output() 1160*cfb92d14SAndroid Build Coastguard Worker host_list = [] 1161*cfb92d14SAndroid Build Coastguard Worker while lines: 1162*cfb92d14SAndroid Build Coastguard Worker host = {} 1163*cfb92d14SAndroid Build Coastguard Worker 1164*cfb92d14SAndroid Build Coastguard Worker host['fullname'] = lines.pop(0).strip() 1165*cfb92d14SAndroid Build Coastguard Worker host['name'] = host['fullname'].split('.')[0] 1166*cfb92d14SAndroid Build Coastguard Worker 1167*cfb92d14SAndroid Build Coastguard Worker host['deleted'] = lines.pop(0).strip().split(':')[1].strip() 1168*cfb92d14SAndroid Build Coastguard Worker if host['deleted'] == 'true': 1169*cfb92d14SAndroid Build Coastguard Worker host_list.append(host) 1170*cfb92d14SAndroid Build Coastguard Worker continue 1171*cfb92d14SAndroid Build Coastguard Worker 1172*cfb92d14SAndroid Build Coastguard Worker addresses = lines.pop(0).strip().split('[')[1].strip(' ]').split(',') 1173*cfb92d14SAndroid Build Coastguard Worker map(str.strip, addresses) 1174*cfb92d14SAndroid Build Coastguard Worker host['addresses'] = [addr.strip() for addr in addresses if addr] 1175*cfb92d14SAndroid Build Coastguard Worker 1176*cfb92d14SAndroid Build Coastguard Worker host_list.append(host) 1177*cfb92d14SAndroid Build Coastguard Worker 1178*cfb92d14SAndroid Build Coastguard Worker return host_list 1179*cfb92d14SAndroid Build Coastguard Worker 1180*cfb92d14SAndroid Build Coastguard Worker def srp_server_get_host(self, host_name): 1181*cfb92d14SAndroid Build Coastguard Worker """Returns host on the SRP server that matches given host name. 1182*cfb92d14SAndroid Build Coastguard Worker 1183*cfb92d14SAndroid Build Coastguard Worker Example usage: 1184*cfb92d14SAndroid Build Coastguard Worker self.srp_server_get_host("my-host") 1185*cfb92d14SAndroid Build Coastguard Worker """ 1186*cfb92d14SAndroid Build Coastguard Worker 1187*cfb92d14SAndroid Build Coastguard Worker for host in self.srp_server_get_hosts(): 1188*cfb92d14SAndroid Build Coastguard Worker if host_name == host['name']: 1189*cfb92d14SAndroid Build Coastguard Worker return host 1190*cfb92d14SAndroid Build Coastguard Worker 1191*cfb92d14SAndroid Build Coastguard Worker def srp_server_get_services(self): 1192*cfb92d14SAndroid Build Coastguard Worker """Returns the service list on the SRP server as a list of property 1193*cfb92d14SAndroid Build Coastguard Worker dictionary. 1194*cfb92d14SAndroid Build Coastguard Worker 1195*cfb92d14SAndroid Build Coastguard Worker Example output: 1196*cfb92d14SAndroid Build Coastguard Worker [{ 1197*cfb92d14SAndroid Build Coastguard Worker 'fullname': 'my-service._ipps._tcp.default.service.arpa.', 1198*cfb92d14SAndroid Build Coastguard Worker 'instance': 'my-service', 1199*cfb92d14SAndroid Build Coastguard Worker 'name': '_ipps._tcp', 1200*cfb92d14SAndroid Build Coastguard Worker 'deleted': 'false', 1201*cfb92d14SAndroid Build Coastguard Worker 'port': '12345', 1202*cfb92d14SAndroid Build Coastguard Worker 'priority': '0', 1203*cfb92d14SAndroid Build Coastguard Worker 'weight': '0', 1204*cfb92d14SAndroid Build Coastguard Worker 'ttl': '7200', 1205*cfb92d14SAndroid Build Coastguard Worker 'lease': '7200', 1206*cfb92d14SAndroid Build Coastguard Worker 'key-lease': '7200', 1207*cfb92d14SAndroid Build Coastguard Worker 'TXT': ['abc=010203'], 1208*cfb92d14SAndroid Build Coastguard Worker 'host_fullname': 'my-host.default.service.arpa.', 1209*cfb92d14SAndroid Build Coastguard Worker 'host': 'my-host', 1210*cfb92d14SAndroid Build Coastguard Worker 'addresses': ['2001::1', '2001::2'] 1211*cfb92d14SAndroid Build Coastguard Worker }] 1212*cfb92d14SAndroid Build Coastguard Worker 1213*cfb92d14SAndroid Build Coastguard Worker Note that the TXT data is output as a HEX string. 1214*cfb92d14SAndroid Build Coastguard Worker """ 1215*cfb92d14SAndroid Build Coastguard Worker 1216*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp server service' 1217*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1218*cfb92d14SAndroid Build Coastguard Worker lines = self._expect_command_output() 1219*cfb92d14SAndroid Build Coastguard Worker 1220*cfb92d14SAndroid Build Coastguard Worker service_list = [] 1221*cfb92d14SAndroid Build Coastguard Worker while lines: 1222*cfb92d14SAndroid Build Coastguard Worker service = {} 1223*cfb92d14SAndroid Build Coastguard Worker 1224*cfb92d14SAndroid Build Coastguard Worker service['fullname'] = lines.pop(0).strip() 1225*cfb92d14SAndroid Build Coastguard Worker name_labels = service['fullname'].split('.') 1226*cfb92d14SAndroid Build Coastguard Worker service['instance'] = name_labels[0] 1227*cfb92d14SAndroid Build Coastguard Worker service['name'] = '.'.join(name_labels[1:3]) 1228*cfb92d14SAndroid Build Coastguard Worker 1229*cfb92d14SAndroid Build Coastguard Worker service['deleted'] = lines.pop(0).strip().split(':')[1].strip() 1230*cfb92d14SAndroid Build Coastguard Worker if service['deleted'] == 'true': 1231*cfb92d14SAndroid Build Coastguard Worker service_list.append(service) 1232*cfb92d14SAndroid Build Coastguard Worker continue 1233*cfb92d14SAndroid Build Coastguard Worker 1234*cfb92d14SAndroid Build Coastguard Worker # 'subtypes', port', 'priority', 'weight', 'ttl', 'lease', and 'key-lease' 1235*cfb92d14SAndroid Build Coastguard Worker for i in range(0, 7): 1236*cfb92d14SAndroid Build Coastguard Worker key_value = lines.pop(0).strip().split(':') 1237*cfb92d14SAndroid Build Coastguard Worker service[key_value[0].strip()] = key_value[1].strip() 1238*cfb92d14SAndroid Build Coastguard Worker 1239*cfb92d14SAndroid Build Coastguard Worker txt_entries = lines.pop(0).strip().split('[')[1].strip(' ]').split(',') 1240*cfb92d14SAndroid Build Coastguard Worker txt_entries = map(str.strip, txt_entries) 1241*cfb92d14SAndroid Build Coastguard Worker service['TXT'] = [txt for txt in txt_entries if txt] 1242*cfb92d14SAndroid Build Coastguard Worker 1243*cfb92d14SAndroid Build Coastguard Worker service['host_fullname'] = lines.pop(0).strip().split(':')[1].strip() 1244*cfb92d14SAndroid Build Coastguard Worker service['host'] = service['host_fullname'].split('.')[0] 1245*cfb92d14SAndroid Build Coastguard Worker 1246*cfb92d14SAndroid Build Coastguard Worker addresses = lines.pop(0).strip().split('[')[1].strip(' ]').split(',') 1247*cfb92d14SAndroid Build Coastguard Worker addresses = map(str.strip, addresses) 1248*cfb92d14SAndroid Build Coastguard Worker service['addresses'] = [addr for addr in addresses if addr] 1249*cfb92d14SAndroid Build Coastguard Worker 1250*cfb92d14SAndroid Build Coastguard Worker service_list.append(service) 1251*cfb92d14SAndroid Build Coastguard Worker 1252*cfb92d14SAndroid Build Coastguard Worker return service_list 1253*cfb92d14SAndroid Build Coastguard Worker 1254*cfb92d14SAndroid Build Coastguard Worker def srp_server_get_service(self, instance_name, service_name): 1255*cfb92d14SAndroid Build Coastguard Worker """Returns service on the SRP server that matches given instance 1256*cfb92d14SAndroid Build Coastguard Worker name and service name. 1257*cfb92d14SAndroid Build Coastguard Worker 1258*cfb92d14SAndroid Build Coastguard Worker Example usage: 1259*cfb92d14SAndroid Build Coastguard Worker self.srp_server_get_service("my-service", "_ipps._tcp") 1260*cfb92d14SAndroid Build Coastguard Worker """ 1261*cfb92d14SAndroid Build Coastguard Worker 1262*cfb92d14SAndroid Build Coastguard Worker for service in self.srp_server_get_services(): 1263*cfb92d14SAndroid Build Coastguard Worker if (instance_name == service['instance'] and service_name == service['name']): 1264*cfb92d14SAndroid Build Coastguard Worker return service 1265*cfb92d14SAndroid Build Coastguard Worker 1266*cfb92d14SAndroid Build Coastguard Worker def get_srp_server_port(self): 1267*cfb92d14SAndroid Build Coastguard Worker """Returns the SRP server UDP port by parsing 1268*cfb92d14SAndroid Build Coastguard Worker the SRP Server Data in Network Data. 1269*cfb92d14SAndroid Build Coastguard Worker """ 1270*cfb92d14SAndroid Build Coastguard Worker 1271*cfb92d14SAndroid Build Coastguard Worker for service in self.get_services(): 1272*cfb92d14SAndroid Build Coastguard Worker # TODO: for now, we are using 0xfd as the SRP service data. 1273*cfb92d14SAndroid Build Coastguard Worker # May use a dedicated bit flag for SRP server. 1274*cfb92d14SAndroid Build Coastguard Worker if int(service[1], 16) == 0x5d: 1275*cfb92d14SAndroid Build Coastguard Worker # The SRP server data contains IPv6 address (16 bytes) 1276*cfb92d14SAndroid Build Coastguard Worker # followed by UDP port number. 1277*cfb92d14SAndroid Build Coastguard Worker return int(service[2][2 * 16:], 16) 1278*cfb92d14SAndroid Build Coastguard Worker 1279*cfb92d14SAndroid Build Coastguard Worker def srp_client_start(self, server_address, server_port): 1280*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client start {server_address} {server_port}') 1281*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1282*cfb92d14SAndroid Build Coastguard Worker 1283*cfb92d14SAndroid Build Coastguard Worker def srp_client_stop(self): 1284*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client stop') 1285*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1286*cfb92d14SAndroid Build Coastguard Worker 1287*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_state(self): 1288*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client state' 1289*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1290*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0] 1291*cfb92d14SAndroid Build Coastguard Worker 1292*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_auto_start_mode(self): 1293*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client autostart' 1294*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1295*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0] 1296*cfb92d14SAndroid Build Coastguard Worker 1297*cfb92d14SAndroid Build Coastguard Worker def srp_client_enable_auto_start_mode(self): 1298*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client autostart enable') 1299*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1300*cfb92d14SAndroid Build Coastguard Worker 1301*cfb92d14SAndroid Build Coastguard Worker def srp_client_disable_auto_start_mode(self): 1302*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client autostart disable') 1303*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1304*cfb92d14SAndroid Build Coastguard Worker 1305*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_server_address(self): 1306*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client server address' 1307*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1308*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0] 1309*cfb92d14SAndroid Build Coastguard Worker 1310*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_server_port(self): 1311*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client server port' 1312*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1313*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_command_output()[0]) 1314*cfb92d14SAndroid Build Coastguard Worker 1315*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_host_state(self): 1316*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client host state' 1317*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1318*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0] 1319*cfb92d14SAndroid Build Coastguard Worker 1320*cfb92d14SAndroid Build Coastguard Worker def srp_client_set_host_name(self, name): 1321*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client host name {name}') 1322*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1323*cfb92d14SAndroid Build Coastguard Worker 1324*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_host_name(self): 1325*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client host name') 1326*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1327*cfb92d14SAndroid Build Coastguard Worker 1328*cfb92d14SAndroid Build Coastguard Worker def srp_client_remove_host(self, remove_key=False, send_unreg_to_server=False): 1329*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client host remove {int(remove_key)} {int(send_unreg_to_server)}') 1330*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1331*cfb92d14SAndroid Build Coastguard Worker 1332*cfb92d14SAndroid Build Coastguard Worker def srp_client_clear_host(self): 1333*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client host clear') 1334*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1335*cfb92d14SAndroid Build Coastguard Worker 1336*cfb92d14SAndroid Build Coastguard Worker def srp_client_enable_auto_host_address(self): 1337*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client host address auto') 1338*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1339*cfb92d14SAndroid Build Coastguard Worker 1340*cfb92d14SAndroid Build Coastguard Worker def srp_client_set_host_address(self, *addrs: str): 1341*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client host address {" ".join(addrs)}') 1342*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1343*cfb92d14SAndroid Build Coastguard Worker 1344*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_host_address(self): 1345*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client host address') 1346*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1347*cfb92d14SAndroid Build Coastguard Worker 1348*cfb92d14SAndroid Build Coastguard Worker def srp_client_add_service(self, 1349*cfb92d14SAndroid Build Coastguard Worker instance_name, 1350*cfb92d14SAndroid Build Coastguard Worker service_name, 1351*cfb92d14SAndroid Build Coastguard Worker port, 1352*cfb92d14SAndroid Build Coastguard Worker priority=0, 1353*cfb92d14SAndroid Build Coastguard Worker weight=0, 1354*cfb92d14SAndroid Build Coastguard Worker txt_entries=[], 1355*cfb92d14SAndroid Build Coastguard Worker lease=0, 1356*cfb92d14SAndroid Build Coastguard Worker key_lease=0): 1357*cfb92d14SAndroid Build Coastguard Worker txt_record = "".join(self._encode_txt_entry(entry) for entry in txt_entries) 1358*cfb92d14SAndroid Build Coastguard Worker if txt_record == '': 1359*cfb92d14SAndroid Build Coastguard Worker txt_record = '-' 1360*cfb92d14SAndroid Build Coastguard Worker instance_name = self._escape_escapable(instance_name) 1361*cfb92d14SAndroid Build Coastguard Worker self.send_command( 1362*cfb92d14SAndroid Build Coastguard Worker f'srp client service add {instance_name} {service_name} {port} {priority} {weight} {txt_record} {lease} {key_lease}' 1363*cfb92d14SAndroid Build Coastguard Worker ) 1364*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1365*cfb92d14SAndroid Build Coastguard Worker 1366*cfb92d14SAndroid Build Coastguard Worker def srp_client_remove_service(self, instance_name, service_name): 1367*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client service remove {instance_name} {service_name}') 1368*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1369*cfb92d14SAndroid Build Coastguard Worker 1370*cfb92d14SAndroid Build Coastguard Worker def srp_client_clear_service(self, instance_name, service_name): 1371*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'srp client service clear {instance_name} {service_name}') 1372*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1373*cfb92d14SAndroid Build Coastguard Worker 1374*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_services(self): 1375*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client service' 1376*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1377*cfb92d14SAndroid Build Coastguard Worker service_lines = self._expect_command_output() 1378*cfb92d14SAndroid Build Coastguard Worker return [self._parse_srp_client_service(line) for line in service_lines] 1379*cfb92d14SAndroid Build Coastguard Worker 1380*cfb92d14SAndroid Build Coastguard Worker def srp_client_set_lease_interval(self, leaseinterval: int): 1381*cfb92d14SAndroid Build Coastguard Worker cmd = f'srp client leaseinterval {leaseinterval}' 1382*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1383*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1384*cfb92d14SAndroid Build Coastguard Worker 1385*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_lease_interval(self) -> int: 1386*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client leaseinterval' 1387*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1388*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_result('\d+')) 1389*cfb92d14SAndroid Build Coastguard Worker 1390*cfb92d14SAndroid Build Coastguard Worker def srp_client_set_key_lease_interval(self, leaseinterval: int): 1391*cfb92d14SAndroid Build Coastguard Worker cmd = f'srp client keyleaseinterval {leaseinterval}' 1392*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1393*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1394*cfb92d14SAndroid Build Coastguard Worker 1395*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_key_lease_interval(self) -> int: 1396*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client keyleaseinterval' 1397*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1398*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_result('\d+')) 1399*cfb92d14SAndroid Build Coastguard Worker 1400*cfb92d14SAndroid Build Coastguard Worker def srp_client_set_ttl(self, ttl: int): 1401*cfb92d14SAndroid Build Coastguard Worker cmd = f'srp client ttl {ttl}' 1402*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1403*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1404*cfb92d14SAndroid Build Coastguard Worker 1405*cfb92d14SAndroid Build Coastguard Worker def srp_client_get_ttl(self) -> int: 1406*cfb92d14SAndroid Build Coastguard Worker cmd = 'srp client ttl' 1407*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1408*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_result('\d+')) 1409*cfb92d14SAndroid Build Coastguard Worker 1410*cfb92d14SAndroid Build Coastguard Worker # 1411*cfb92d14SAndroid Build Coastguard Worker # TREL utilities 1412*cfb92d14SAndroid Build Coastguard Worker # 1413*cfb92d14SAndroid Build Coastguard Worker 1414*cfb92d14SAndroid Build Coastguard Worker def enable_trel(self): 1415*cfb92d14SAndroid Build Coastguard Worker cmd = 'trel enable' 1416*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1417*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1418*cfb92d14SAndroid Build Coastguard Worker 1419*cfb92d14SAndroid Build Coastguard Worker def is_trel_enabled(self) -> Union[None, bool]: 1420*cfb92d14SAndroid Build Coastguard Worker states = [r'Disabled', r'Enabled'] 1421*cfb92d14SAndroid Build Coastguard Worker self.send_command('trel') 1422*cfb92d14SAndroid Build Coastguard Worker try: 1423*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(states) == 'Enabled' 1424*cfb92d14SAndroid Build Coastguard Worker except Exception as ex: 1425*cfb92d14SAndroid Build Coastguard Worker if 'InvalidCommand' in str(ex): 1426*cfb92d14SAndroid Build Coastguard Worker return None 1427*cfb92d14SAndroid Build Coastguard Worker 1428*cfb92d14SAndroid Build Coastguard Worker raise 1429*cfb92d14SAndroid Build Coastguard Worker 1430*cfb92d14SAndroid Build Coastguard Worker def get_trel_counters(self): 1431*cfb92d14SAndroid Build Coastguard Worker cmd = 'trel counters' 1432*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1433*cfb92d14SAndroid Build Coastguard Worker result = self._expect_command_output() 1434*cfb92d14SAndroid Build Coastguard Worker 1435*cfb92d14SAndroid Build Coastguard Worker counters = {} 1436*cfb92d14SAndroid Build Coastguard Worker for line in result: 1437*cfb92d14SAndroid Build Coastguard Worker m = re.match(r'(\w+)\:[^\d]+(\d+)[^\d]+(\d+)(?:[^\d]+(\d+))?', line) 1438*cfb92d14SAndroid Build Coastguard Worker if m: 1439*cfb92d14SAndroid Build Coastguard Worker groups = m.groups() 1440*cfb92d14SAndroid Build Coastguard Worker sub_counters = { 1441*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[1]), 1442*cfb92d14SAndroid Build Coastguard Worker 'bytes': int(groups[2]), 1443*cfb92d14SAndroid Build Coastguard Worker } 1444*cfb92d14SAndroid Build Coastguard Worker if groups[3]: 1445*cfb92d14SAndroid Build Coastguard Worker sub_counters['failures'] = int(groups[3]) 1446*cfb92d14SAndroid Build Coastguard Worker counters[groups[0]] = sub_counters 1447*cfb92d14SAndroid Build Coastguard Worker return counters 1448*cfb92d14SAndroid Build Coastguard Worker 1449*cfb92d14SAndroid Build Coastguard Worker def reset_trel_counters(self): 1450*cfb92d14SAndroid Build Coastguard Worker cmd = 'trel counters reset' 1451*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1452*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1453*cfb92d14SAndroid Build Coastguard Worker 1454*cfb92d14SAndroid Build Coastguard Worker def get_trel_port(self): 1455*cfb92d14SAndroid Build Coastguard Worker cmd = 'trel port' 1456*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1457*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_command_output()[0]) 1458*cfb92d14SAndroid Build Coastguard Worker 1459*cfb92d14SAndroid Build Coastguard Worker def set_epskc(self, keystring: str, timeout=120000, port=0): 1460*cfb92d14SAndroid Build Coastguard Worker cmd = 'ba ephemeralkey set ' + keystring + ' ' + str(timeout) + ' ' + str(port) 1461*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1462*cfb92d14SAndroid Build Coastguard Worker self._expect(r"(Done|Error .*)") 1463*cfb92d14SAndroid Build Coastguard Worker 1464*cfb92d14SAndroid Build Coastguard Worker def clear_epskc(self): 1465*cfb92d14SAndroid Build Coastguard Worker cmd = 'ba ephemeralkey clear' 1466*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1467*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1468*cfb92d14SAndroid Build Coastguard Worker 1469*cfb92d14SAndroid Build Coastguard Worker def get_border_agent_counters(self): 1470*cfb92d14SAndroid Build Coastguard Worker cmd = 'ba counters' 1471*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1472*cfb92d14SAndroid Build Coastguard Worker result = self._expect_command_output() 1473*cfb92d14SAndroid Build Coastguard Worker 1474*cfb92d14SAndroid Build Coastguard Worker counters = {} 1475*cfb92d14SAndroid Build Coastguard Worker for line in result: 1476*cfb92d14SAndroid Build Coastguard Worker m = re.match(r'(\w+)\: (\d+)', line) 1477*cfb92d14SAndroid Build Coastguard Worker if m: 1478*cfb92d14SAndroid Build Coastguard Worker counter_name = m.group(1) 1479*cfb92d14SAndroid Build Coastguard Worker counter_value = m.group(2) 1480*cfb92d14SAndroid Build Coastguard Worker 1481*cfb92d14SAndroid Build Coastguard Worker counters[counter_name] = int(counter_value) 1482*cfb92d14SAndroid Build Coastguard Worker return counters 1483*cfb92d14SAndroid Build Coastguard Worker 1484*cfb92d14SAndroid Build Coastguard Worker def _encode_txt_entry(self, entry): 1485*cfb92d14SAndroid Build Coastguard Worker """Encodes the TXT entry to the DNS-SD TXT record format as a HEX string. 1486*cfb92d14SAndroid Build Coastguard Worker 1487*cfb92d14SAndroid Build Coastguard Worker Example usage: 1488*cfb92d14SAndroid Build Coastguard Worker self._encode_txt_entries(['abc']) -> '03616263' 1489*cfb92d14SAndroid Build Coastguard Worker self._encode_txt_entries(['def=']) -> '046465663d' 1490*cfb92d14SAndroid Build Coastguard Worker self._encode_txt_entries(['xyz=XYZ']) -> '0778797a3d58595a' 1491*cfb92d14SAndroid Build Coastguard Worker """ 1492*cfb92d14SAndroid Build Coastguard Worker return '{:02x}'.format(len(entry)) + "".join("{:02x}".format(ord(c)) for c in entry) 1493*cfb92d14SAndroid Build Coastguard Worker 1494*cfb92d14SAndroid Build Coastguard Worker def _parse_srp_client_service(self, line: str): 1495*cfb92d14SAndroid Build Coastguard Worker """Parse one line of srp service list into a dictionary which 1496*cfb92d14SAndroid Build Coastguard Worker maps string keys to string values. 1497*cfb92d14SAndroid Build Coastguard Worker 1498*cfb92d14SAndroid Build Coastguard Worker Example output for input 1499*cfb92d14SAndroid Build Coastguard Worker 'instance:\"%s\", name:\"%s\", state:%s, port:%d, priority:%d, weight:%d"' 1500*cfb92d14SAndroid Build Coastguard Worker { 1501*cfb92d14SAndroid Build Coastguard Worker 'instance': 'my-service', 1502*cfb92d14SAndroid Build Coastguard Worker 'name': '_ipps._udp', 1503*cfb92d14SAndroid Build Coastguard Worker 'state': 'ToAdd', 1504*cfb92d14SAndroid Build Coastguard Worker 'port': '12345', 1505*cfb92d14SAndroid Build Coastguard Worker 'priority': '0', 1506*cfb92d14SAndroid Build Coastguard Worker 'weight': '0' 1507*cfb92d14SAndroid Build Coastguard Worker } 1508*cfb92d14SAndroid Build Coastguard Worker 1509*cfb92d14SAndroid Build Coastguard Worker Note that value of 'port', 'priority' and 'weight' are represented 1510*cfb92d14SAndroid Build Coastguard Worker as strings but not integers. 1511*cfb92d14SAndroid Build Coastguard Worker """ 1512*cfb92d14SAndroid Build Coastguard Worker key_values = [word.strip().split(':') for word in line.split(', ')] 1513*cfb92d14SAndroid Build Coastguard Worker keys = [key_value[0] for key_value in key_values] 1514*cfb92d14SAndroid Build Coastguard Worker values = [key_value[1].strip('"') for key_value in key_values] 1515*cfb92d14SAndroid Build Coastguard Worker return dict(zip(keys, values)) 1516*cfb92d14SAndroid Build Coastguard Worker 1517*cfb92d14SAndroid Build Coastguard Worker def locate(self, anycast_addr): 1518*cfb92d14SAndroid Build Coastguard Worker cmd = 'locate ' + anycast_addr 1519*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1520*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 1521*cfb92d14SAndroid Build Coastguard Worker return self._parse_locate_result(self._expect_command_output()[0]) 1522*cfb92d14SAndroid Build Coastguard Worker 1523*cfb92d14SAndroid Build Coastguard Worker def _parse_locate_result(self, line: str): 1524*cfb92d14SAndroid Build Coastguard Worker """Parse anycast locate result as list of ml-eid and rloc16. 1525*cfb92d14SAndroid Build Coastguard Worker 1526*cfb92d14SAndroid Build Coastguard Worker Example output for input 1527*cfb92d14SAndroid Build Coastguard Worker 'fd00:db8:0:0:acf9:9d0:7f3c:b06e 0xa800' 1528*cfb92d14SAndroid Build Coastguard Worker 1529*cfb92d14SAndroid Build Coastguard Worker [ 'fd00:db8:0:0:acf9:9d0:7f3c:b06e', '0xa800' ] 1530*cfb92d14SAndroid Build Coastguard Worker """ 1531*cfb92d14SAndroid Build Coastguard Worker return line.split(' ') 1532*cfb92d14SAndroid Build Coastguard Worker 1533*cfb92d14SAndroid Build Coastguard Worker def enable_backbone_router(self): 1534*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr enable' 1535*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1536*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1537*cfb92d14SAndroid Build Coastguard Worker 1538*cfb92d14SAndroid Build Coastguard Worker def disable_backbone_router(self): 1539*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr disable' 1540*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1541*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1542*cfb92d14SAndroid Build Coastguard Worker 1543*cfb92d14SAndroid Build Coastguard Worker def register_backbone_router(self): 1544*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr register' 1545*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1546*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1547*cfb92d14SAndroid Build Coastguard Worker 1548*cfb92d14SAndroid Build Coastguard Worker def get_backbone_router_state(self): 1549*cfb92d14SAndroid Build Coastguard Worker states = [r'Disabled', r'Primary', r'Secondary'] 1550*cfb92d14SAndroid Build Coastguard Worker self.send_command('bbr state') 1551*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(states) 1552*cfb92d14SAndroid Build Coastguard Worker 1553*cfb92d14SAndroid Build Coastguard Worker @property 1554*cfb92d14SAndroid Build Coastguard Worker def is_primary_backbone_router(self) -> bool: 1555*cfb92d14SAndroid Build Coastguard Worker return self.get_backbone_router_state() == 'Primary' 1556*cfb92d14SAndroid Build Coastguard Worker 1557*cfb92d14SAndroid Build Coastguard Worker def get_backbone_router(self): 1558*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr config' 1559*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1560*cfb92d14SAndroid Build Coastguard Worker self._expect(r'(.*)Done') 1561*cfb92d14SAndroid Build Coastguard Worker g = self.pexpect.match.groups() 1562*cfb92d14SAndroid Build Coastguard Worker output = g[0].decode("utf-8") 1563*cfb92d14SAndroid Build Coastguard Worker lines = output.strip().split('\n') 1564*cfb92d14SAndroid Build Coastguard Worker lines = [l.strip() for l in lines] 1565*cfb92d14SAndroid Build Coastguard Worker ret = {} 1566*cfb92d14SAndroid Build Coastguard Worker for l in lines: 1567*cfb92d14SAndroid Build Coastguard Worker z = re.search(r'seqno:\s+([0-9]+)', l) 1568*cfb92d14SAndroid Build Coastguard Worker if z: 1569*cfb92d14SAndroid Build Coastguard Worker ret['seqno'] = int(z.groups()[0]) 1570*cfb92d14SAndroid Build Coastguard Worker 1571*cfb92d14SAndroid Build Coastguard Worker z = re.search(r'delay:\s+([0-9]+)', l) 1572*cfb92d14SAndroid Build Coastguard Worker if z: 1573*cfb92d14SAndroid Build Coastguard Worker ret['delay'] = int(z.groups()[0]) 1574*cfb92d14SAndroid Build Coastguard Worker 1575*cfb92d14SAndroid Build Coastguard Worker z = re.search(r'timeout:\s+([0-9]+)', l) 1576*cfb92d14SAndroid Build Coastguard Worker if z: 1577*cfb92d14SAndroid Build Coastguard Worker ret['timeout'] = int(z.groups()[0]) 1578*cfb92d14SAndroid Build Coastguard Worker 1579*cfb92d14SAndroid Build Coastguard Worker return ret 1580*cfb92d14SAndroid Build Coastguard Worker 1581*cfb92d14SAndroid Build Coastguard Worker def set_backbone_router(self, seqno=None, reg_delay=None, mlr_timeout=None): 1582*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr config' 1583*cfb92d14SAndroid Build Coastguard Worker 1584*cfb92d14SAndroid Build Coastguard Worker if seqno is not None: 1585*cfb92d14SAndroid Build Coastguard Worker cmd += ' seqno %d' % seqno 1586*cfb92d14SAndroid Build Coastguard Worker 1587*cfb92d14SAndroid Build Coastguard Worker if reg_delay is not None: 1588*cfb92d14SAndroid Build Coastguard Worker cmd += ' delay %d' % reg_delay 1589*cfb92d14SAndroid Build Coastguard Worker 1590*cfb92d14SAndroid Build Coastguard Worker if mlr_timeout is not None: 1591*cfb92d14SAndroid Build Coastguard Worker cmd += ' timeout %d' % mlr_timeout 1592*cfb92d14SAndroid Build Coastguard Worker 1593*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1594*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1595*cfb92d14SAndroid Build Coastguard Worker 1596*cfb92d14SAndroid Build Coastguard Worker def set_domain_prefix(self, prefix, flags='prosD'): 1597*cfb92d14SAndroid Build Coastguard Worker self.add_prefix(prefix, flags) 1598*cfb92d14SAndroid Build Coastguard Worker self.register_netdata() 1599*cfb92d14SAndroid Build Coastguard Worker 1600*cfb92d14SAndroid Build Coastguard Worker def remove_domain_prefix(self, prefix): 1601*cfb92d14SAndroid Build Coastguard Worker self.remove_prefix(prefix) 1602*cfb92d14SAndroid Build Coastguard Worker self.register_netdata() 1603*cfb92d14SAndroid Build Coastguard Worker 1604*cfb92d14SAndroid Build Coastguard Worker def set_next_dua_response(self, status: Union[str, int], iid=None): 1605*cfb92d14SAndroid Build Coastguard Worker # Convert 5.00 to COAP CODE 160 1606*cfb92d14SAndroid Build Coastguard Worker if isinstance(status, str): 1607*cfb92d14SAndroid Build Coastguard Worker assert '.' in status 1608*cfb92d14SAndroid Build Coastguard Worker status = status.split('.') 1609*cfb92d14SAndroid Build Coastguard Worker status = (int(status[0]) << 5) + int(status[1]) 1610*cfb92d14SAndroid Build Coastguard Worker 1611*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr mgmt dua {}'.format(status) 1612*cfb92d14SAndroid Build Coastguard Worker if iid is not None: 1613*cfb92d14SAndroid Build Coastguard Worker cmd += ' ' + str(iid) 1614*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1615*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1616*cfb92d14SAndroid Build Coastguard Worker 1617*cfb92d14SAndroid Build Coastguard Worker def set_dua_iid(self, iid: str): 1618*cfb92d14SAndroid Build Coastguard Worker assert len(iid) == 16 1619*cfb92d14SAndroid Build Coastguard Worker int(iid, 16) 1620*cfb92d14SAndroid Build Coastguard Worker 1621*cfb92d14SAndroid Build Coastguard Worker cmd = 'dua iid {}'.format(iid) 1622*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1623*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1624*cfb92d14SAndroid Build Coastguard Worker 1625*cfb92d14SAndroid Build Coastguard Worker def clear_dua_iid(self): 1626*cfb92d14SAndroid Build Coastguard Worker cmd = 'dua iid clear' 1627*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1628*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1629*cfb92d14SAndroid Build Coastguard Worker 1630*cfb92d14SAndroid Build Coastguard Worker def multicast_listener_list(self) -> Dict[IPv6Address, int]: 1631*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr mgmt mlr listener' 1632*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1633*cfb92d14SAndroid Build Coastguard Worker 1634*cfb92d14SAndroid Build Coastguard Worker table = {} 1635*cfb92d14SAndroid Build Coastguard Worker for line in self._expect_results("\S+ \d+"): 1636*cfb92d14SAndroid Build Coastguard Worker line = line.split() 1637*cfb92d14SAndroid Build Coastguard Worker assert len(line) == 2, line 1638*cfb92d14SAndroid Build Coastguard Worker ip = IPv6Address(line[0]) 1639*cfb92d14SAndroid Build Coastguard Worker timeout = int(line[1]) 1640*cfb92d14SAndroid Build Coastguard Worker assert ip not in table 1641*cfb92d14SAndroid Build Coastguard Worker 1642*cfb92d14SAndroid Build Coastguard Worker table[ip] = timeout 1643*cfb92d14SAndroid Build Coastguard Worker 1644*cfb92d14SAndroid Build Coastguard Worker return table 1645*cfb92d14SAndroid Build Coastguard Worker 1646*cfb92d14SAndroid Build Coastguard Worker def multicast_listener_clear(self): 1647*cfb92d14SAndroid Build Coastguard Worker cmd = f'bbr mgmt mlr listener clear' 1648*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1649*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1650*cfb92d14SAndroid Build Coastguard Worker 1651*cfb92d14SAndroid Build Coastguard Worker def multicast_listener_add(self, ip: Union[IPv6Address, str], timeout: int = 0): 1652*cfb92d14SAndroid Build Coastguard Worker if not isinstance(ip, IPv6Address): 1653*cfb92d14SAndroid Build Coastguard Worker ip = IPv6Address(ip) 1654*cfb92d14SAndroid Build Coastguard Worker 1655*cfb92d14SAndroid Build Coastguard Worker cmd = f'bbr mgmt mlr listener add {ip.compressed} {timeout}' 1656*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1657*cfb92d14SAndroid Build Coastguard Worker self._expect(r"(Done|Error .*)") 1658*cfb92d14SAndroid Build Coastguard Worker 1659*cfb92d14SAndroid Build Coastguard Worker def set_next_mlr_response(self, status: int): 1660*cfb92d14SAndroid Build Coastguard Worker cmd = 'bbr mgmt mlr response {}'.format(status) 1661*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1662*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1663*cfb92d14SAndroid Build Coastguard Worker 1664*cfb92d14SAndroid Build Coastguard Worker def register_multicast_listener(self, *ipaddrs: Union[IPv6Address, str], timeout=None): 1665*cfb92d14SAndroid Build Coastguard Worker assert len(ipaddrs) > 0, ipaddrs 1666*cfb92d14SAndroid Build Coastguard Worker 1667*cfb92d14SAndroid Build Coastguard Worker ipaddrs = map(str, ipaddrs) 1668*cfb92d14SAndroid Build Coastguard Worker cmd = f'mlr reg {" ".join(ipaddrs)}' 1669*cfb92d14SAndroid Build Coastguard Worker if timeout is not None: 1670*cfb92d14SAndroid Build Coastguard Worker cmd += f' {int(timeout)}' 1671*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1672*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(3) 1673*cfb92d14SAndroid Build Coastguard Worker lines = self._expect_command_output() 1674*cfb92d14SAndroid Build Coastguard Worker m = re.match(r'status (\d+), (\d+) failed', lines[0]) 1675*cfb92d14SAndroid Build Coastguard Worker assert m is not None, lines 1676*cfb92d14SAndroid Build Coastguard Worker status = int(m.group(1)) 1677*cfb92d14SAndroid Build Coastguard Worker failed_num = int(m.group(2)) 1678*cfb92d14SAndroid Build Coastguard Worker assert failed_num == len(lines) - 1 1679*cfb92d14SAndroid Build Coastguard Worker failed_ips = list(map(IPv6Address, lines[1:])) 1680*cfb92d14SAndroid Build Coastguard Worker print(f"register_multicast_listener {ipaddrs} => status: {status}, failed ips: {failed_ips}") 1681*cfb92d14SAndroid Build Coastguard Worker return status, failed_ips 1682*cfb92d14SAndroid Build Coastguard Worker 1683*cfb92d14SAndroid Build Coastguard Worker def set_link_quality(self, addr, lqi): 1684*cfb92d14SAndroid Build Coastguard Worker cmd = 'macfilter rss add-lqi %s %s' % (addr, lqi) 1685*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1686*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1687*cfb92d14SAndroid Build Coastguard Worker 1688*cfb92d14SAndroid Build Coastguard Worker def set_outbound_link_quality(self, lqi): 1689*cfb92d14SAndroid Build Coastguard Worker cmd = 'macfilter rss add-lqi * %s' % (lqi) 1690*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1691*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1692*cfb92d14SAndroid Build Coastguard Worker 1693*cfb92d14SAndroid Build Coastguard Worker def remove_allowlist(self, addr): 1694*cfb92d14SAndroid Build Coastguard Worker cmd = 'macfilter addr remove %s' % addr 1695*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1696*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1697*cfb92d14SAndroid Build Coastguard Worker 1698*cfb92d14SAndroid Build Coastguard Worker def get_addr16(self): 1699*cfb92d14SAndroid Build Coastguard Worker self.send_command('rloc16') 1700*cfb92d14SAndroid Build Coastguard Worker rloc16 = self._expect_result(r'[0-9a-fA-F]{4}') 1701*cfb92d14SAndroid Build Coastguard Worker return int(rloc16, 16) 1702*cfb92d14SAndroid Build Coastguard Worker 1703*cfb92d14SAndroid Build Coastguard Worker def get_router_id(self): 1704*cfb92d14SAndroid Build Coastguard Worker rloc16 = self.get_addr16() 1705*cfb92d14SAndroid Build Coastguard Worker return rloc16 >> 10 1706*cfb92d14SAndroid Build Coastguard Worker 1707*cfb92d14SAndroid Build Coastguard Worker def get_addr64(self): 1708*cfb92d14SAndroid Build Coastguard Worker self.send_command('extaddr') 1709*cfb92d14SAndroid Build Coastguard Worker return self._expect_result('[0-9a-fA-F]{16}') 1710*cfb92d14SAndroid Build Coastguard Worker 1711*cfb92d14SAndroid Build Coastguard Worker def set_addr64(self, addr64: str): 1712*cfb92d14SAndroid Build Coastguard Worker # Make sure `addr64` is a hex string of length 16 1713*cfb92d14SAndroid Build Coastguard Worker assert len(addr64) == 16 1714*cfb92d14SAndroid Build Coastguard Worker int(addr64, 16) 1715*cfb92d14SAndroid Build Coastguard Worker self.send_command('extaddr %s' % addr64) 1716*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1717*cfb92d14SAndroid Build Coastguard Worker 1718*cfb92d14SAndroid Build Coastguard Worker def get_eui64(self): 1719*cfb92d14SAndroid Build Coastguard Worker self.send_command('eui64') 1720*cfb92d14SAndroid Build Coastguard Worker return self._expect_result('[0-9a-fA-F]{16}') 1721*cfb92d14SAndroid Build Coastguard Worker 1722*cfb92d14SAndroid Build Coastguard Worker def set_extpanid(self, extpanid): 1723*cfb92d14SAndroid Build Coastguard Worker self.send_command('extpanid %s' % extpanid) 1724*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1725*cfb92d14SAndroid Build Coastguard Worker 1726*cfb92d14SAndroid Build Coastguard Worker def get_extpanid(self): 1727*cfb92d14SAndroid Build Coastguard Worker self.send_command('extpanid') 1728*cfb92d14SAndroid Build Coastguard Worker return self._expect_result('[0-9a-fA-F]{16}') 1729*cfb92d14SAndroid Build Coastguard Worker 1730*cfb92d14SAndroid Build Coastguard Worker def get_mesh_local_prefix(self): 1731*cfb92d14SAndroid Build Coastguard Worker self.send_command('prefix meshlocal') 1732*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0] 1733*cfb92d14SAndroid Build Coastguard Worker 1734*cfb92d14SAndroid Build Coastguard Worker def set_mesh_local_prefix(self, mesh_local_prefix): 1735*cfb92d14SAndroid Build Coastguard Worker self.send_command('prefix meshlocal %s' % mesh_local_prefix) 1736*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1737*cfb92d14SAndroid Build Coastguard Worker 1738*cfb92d14SAndroid Build Coastguard Worker def get_joiner_id(self): 1739*cfb92d14SAndroid Build Coastguard Worker self.send_command('joiner id') 1740*cfb92d14SAndroid Build Coastguard Worker return self._expect_result('[0-9a-fA-F]{16}') 1741*cfb92d14SAndroid Build Coastguard Worker 1742*cfb92d14SAndroid Build Coastguard Worker def get_channel(self): 1743*cfb92d14SAndroid Build Coastguard Worker self.send_command('channel') 1744*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_result(r'\d+')) 1745*cfb92d14SAndroid Build Coastguard Worker 1746*cfb92d14SAndroid Build Coastguard Worker def set_channel(self, channel): 1747*cfb92d14SAndroid Build Coastguard Worker cmd = 'channel %d' % channel 1748*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1749*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1750*cfb92d14SAndroid Build Coastguard Worker 1751*cfb92d14SAndroid Build Coastguard Worker def get_networkkey(self): 1752*cfb92d14SAndroid Build Coastguard Worker self.send_command('networkkey') 1753*cfb92d14SAndroid Build Coastguard Worker return self._expect_result('[0-9a-fA-F]{32}') 1754*cfb92d14SAndroid Build Coastguard Worker 1755*cfb92d14SAndroid Build Coastguard Worker def set_networkkey(self, networkkey): 1756*cfb92d14SAndroid Build Coastguard Worker cmd = 'networkkey %s' % networkkey 1757*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1758*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1759*cfb92d14SAndroid Build Coastguard Worker 1760*cfb92d14SAndroid Build Coastguard Worker def get_key_sequence_counter(self): 1761*cfb92d14SAndroid Build Coastguard Worker self.send_command('keysequence counter') 1762*cfb92d14SAndroid Build Coastguard Worker result = self._expect_result(r'\d+') 1763*cfb92d14SAndroid Build Coastguard Worker return int(result) 1764*cfb92d14SAndroid Build Coastguard Worker 1765*cfb92d14SAndroid Build Coastguard Worker def set_key_sequence_counter(self, key_sequence_counter): 1766*cfb92d14SAndroid Build Coastguard Worker cmd = 'keysequence counter %d' % key_sequence_counter 1767*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1768*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1769*cfb92d14SAndroid Build Coastguard Worker 1770*cfb92d14SAndroid Build Coastguard Worker def get_key_switch_guardtime(self): 1771*cfb92d14SAndroid Build Coastguard Worker self.send_command('keysequence guardtime') 1772*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_result(r'\d+')) 1773*cfb92d14SAndroid Build Coastguard Worker 1774*cfb92d14SAndroid Build Coastguard Worker def set_key_switch_guardtime(self, key_switch_guardtime): 1775*cfb92d14SAndroid Build Coastguard Worker cmd = 'keysequence guardtime %d' % key_switch_guardtime 1776*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1777*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1778*cfb92d14SAndroid Build Coastguard Worker 1779*cfb92d14SAndroid Build Coastguard Worker def set_network_id_timeout(self, network_id_timeout): 1780*cfb92d14SAndroid Build Coastguard Worker cmd = 'networkidtimeout %d' % network_id_timeout 1781*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1782*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1783*cfb92d14SAndroid Build Coastguard Worker 1784*cfb92d14SAndroid Build Coastguard Worker def _escape_escapable(self, string): 1785*cfb92d14SAndroid Build Coastguard Worker """Escape CLI escapable characters in the given string. 1786*cfb92d14SAndroid Build Coastguard Worker 1787*cfb92d14SAndroid Build Coastguard Worker Args: 1788*cfb92d14SAndroid Build Coastguard Worker string (str): UTF-8 input string. 1789*cfb92d14SAndroid Build Coastguard Worker 1790*cfb92d14SAndroid Build Coastguard Worker Returns: 1791*cfb92d14SAndroid Build Coastguard Worker [str]: The modified string with escaped characters. 1792*cfb92d14SAndroid Build Coastguard Worker """ 1793*cfb92d14SAndroid Build Coastguard Worker escapable_chars = '\\ \t\r\n' 1794*cfb92d14SAndroid Build Coastguard Worker for char in escapable_chars: 1795*cfb92d14SAndroid Build Coastguard Worker string = string.replace(char, '\\%s' % char) 1796*cfb92d14SAndroid Build Coastguard Worker return string 1797*cfb92d14SAndroid Build Coastguard Worker 1798*cfb92d14SAndroid Build Coastguard Worker def get_network_name(self): 1799*cfb92d14SAndroid Build Coastguard Worker self.send_command('networkname') 1800*cfb92d14SAndroid Build Coastguard Worker return self._expect_result([r'\S+']) 1801*cfb92d14SAndroid Build Coastguard Worker 1802*cfb92d14SAndroid Build Coastguard Worker def set_network_name(self, network_name): 1803*cfb92d14SAndroid Build Coastguard Worker cmd = 'networkname %s' % self._escape_escapable(network_name) 1804*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1805*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1806*cfb92d14SAndroid Build Coastguard Worker 1807*cfb92d14SAndroid Build Coastguard Worker def get_panid(self): 1808*cfb92d14SAndroid Build Coastguard Worker self.send_command('panid') 1809*cfb92d14SAndroid Build Coastguard Worker result = self._expect_result('0x[0-9a-fA-F]{4}') 1810*cfb92d14SAndroid Build Coastguard Worker return int(result, 16) 1811*cfb92d14SAndroid Build Coastguard Worker 1812*cfb92d14SAndroid Build Coastguard Worker def set_panid(self, panid=config.PANID): 1813*cfb92d14SAndroid Build Coastguard Worker cmd = 'panid %d' % panid 1814*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1815*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1816*cfb92d14SAndroid Build Coastguard Worker 1817*cfb92d14SAndroid Build Coastguard Worker def set_parent_priority(self, priority): 1818*cfb92d14SAndroid Build Coastguard Worker cmd = 'parentpriority %d' % priority 1819*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1820*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1821*cfb92d14SAndroid Build Coastguard Worker 1822*cfb92d14SAndroid Build Coastguard Worker def get_partition_id(self): 1823*cfb92d14SAndroid Build Coastguard Worker self.send_command('partitionid') 1824*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 1825*cfb92d14SAndroid Build Coastguard Worker 1826*cfb92d14SAndroid Build Coastguard Worker def get_preferred_partition_id(self): 1827*cfb92d14SAndroid Build Coastguard Worker self.send_command('partitionid preferred') 1828*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 1829*cfb92d14SAndroid Build Coastguard Worker 1830*cfb92d14SAndroid Build Coastguard Worker def set_preferred_partition_id(self, partition_id): 1831*cfb92d14SAndroid Build Coastguard Worker cmd = 'partitionid preferred %d' % partition_id 1832*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1833*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1834*cfb92d14SAndroid Build Coastguard Worker 1835*cfb92d14SAndroid Build Coastguard Worker def get_pollperiod(self): 1836*cfb92d14SAndroid Build Coastguard Worker self.send_command('pollperiod') 1837*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 1838*cfb92d14SAndroid Build Coastguard Worker 1839*cfb92d14SAndroid Build Coastguard Worker def set_pollperiod(self, pollperiod): 1840*cfb92d14SAndroid Build Coastguard Worker self.send_command('pollperiod %d' % pollperiod) 1841*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1842*cfb92d14SAndroid Build Coastguard Worker 1843*cfb92d14SAndroid Build Coastguard Worker def get_child_supervision_interval(self): 1844*cfb92d14SAndroid Build Coastguard Worker self.send_command('childsupervision interval') 1845*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 1846*cfb92d14SAndroid Build Coastguard Worker 1847*cfb92d14SAndroid Build Coastguard Worker def set_child_supervision_interval(self, interval): 1848*cfb92d14SAndroid Build Coastguard Worker self.send_command('childsupervision interval %d' % interval) 1849*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1850*cfb92d14SAndroid Build Coastguard Worker 1851*cfb92d14SAndroid Build Coastguard Worker def get_child_supervision_check_timeout(self): 1852*cfb92d14SAndroid Build Coastguard Worker self.send_command('childsupervision checktimeout') 1853*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 1854*cfb92d14SAndroid Build Coastguard Worker 1855*cfb92d14SAndroid Build Coastguard Worker def set_child_supervision_check_timeout(self, timeout): 1856*cfb92d14SAndroid Build Coastguard Worker self.send_command('childsupervision checktimeout %d' % timeout) 1857*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1858*cfb92d14SAndroid Build Coastguard Worker 1859*cfb92d14SAndroid Build Coastguard Worker def get_child_supervision_check_failure_counter(self): 1860*cfb92d14SAndroid Build Coastguard Worker self.send_command('childsupervision failcounter') 1861*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 1862*cfb92d14SAndroid Build Coastguard Worker 1863*cfb92d14SAndroid Build Coastguard Worker def reset_child_supervision_check_failure_counter(self): 1864*cfb92d14SAndroid Build Coastguard Worker self.send_command('childsupervision failcounter reset') 1865*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1866*cfb92d14SAndroid Build Coastguard Worker 1867*cfb92d14SAndroid Build Coastguard Worker def get_csl_info(self): 1868*cfb92d14SAndroid Build Coastguard Worker self.send_command('csl') 1869*cfb92d14SAndroid Build Coastguard Worker return self._expect_key_value_pairs(r'\S+') 1870*cfb92d14SAndroid Build Coastguard Worker 1871*cfb92d14SAndroid Build Coastguard Worker def set_csl_channel(self, csl_channel): 1872*cfb92d14SAndroid Build Coastguard Worker self.send_command('csl channel %d' % csl_channel) 1873*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1874*cfb92d14SAndroid Build Coastguard Worker 1875*cfb92d14SAndroid Build Coastguard Worker def set_csl_period(self, csl_period): 1876*cfb92d14SAndroid Build Coastguard Worker self.send_command('csl period %d' % csl_period) 1877*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1878*cfb92d14SAndroid Build Coastguard Worker 1879*cfb92d14SAndroid Build Coastguard Worker def set_csl_timeout(self, csl_timeout): 1880*cfb92d14SAndroid Build Coastguard Worker self.send_command('csl timeout %d' % csl_timeout) 1881*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1882*cfb92d14SAndroid Build Coastguard Worker 1883*cfb92d14SAndroid Build Coastguard Worker def send_mac_emptydata(self): 1884*cfb92d14SAndroid Build Coastguard Worker self.send_command('mac send emptydata') 1885*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1886*cfb92d14SAndroid Build Coastguard Worker 1887*cfb92d14SAndroid Build Coastguard Worker def send_mac_datarequest(self): 1888*cfb92d14SAndroid Build Coastguard Worker self.send_command('mac send datarequest') 1889*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1890*cfb92d14SAndroid Build Coastguard Worker 1891*cfb92d14SAndroid Build Coastguard Worker def set_router_upgrade_threshold(self, threshold): 1892*cfb92d14SAndroid Build Coastguard Worker cmd = 'routerupgradethreshold %d' % threshold 1893*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1894*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1895*cfb92d14SAndroid Build Coastguard Worker 1896*cfb92d14SAndroid Build Coastguard Worker def set_router_downgrade_threshold(self, threshold): 1897*cfb92d14SAndroid Build Coastguard Worker cmd = 'routerdowngradethreshold %d' % threshold 1898*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1899*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1900*cfb92d14SAndroid Build Coastguard Worker 1901*cfb92d14SAndroid Build Coastguard Worker def get_router_downgrade_threshold(self) -> int: 1902*cfb92d14SAndroid Build Coastguard Worker self.send_command('routerdowngradethreshold') 1903*cfb92d14SAndroid Build Coastguard Worker return int(self._expect_result(r'\d+')) 1904*cfb92d14SAndroid Build Coastguard Worker 1905*cfb92d14SAndroid Build Coastguard Worker def set_router_eligible(self, enable: bool): 1906*cfb92d14SAndroid Build Coastguard Worker cmd = f'routereligible {"enable" if enable else "disable"}' 1907*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1908*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1909*cfb92d14SAndroid Build Coastguard Worker 1910*cfb92d14SAndroid Build Coastguard Worker def get_router_eligible(self) -> bool: 1911*cfb92d14SAndroid Build Coastguard Worker states = [r'Disabled', r'Enabled'] 1912*cfb92d14SAndroid Build Coastguard Worker self.send_command('routereligible') 1913*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(states) == 'Enabled' 1914*cfb92d14SAndroid Build Coastguard Worker 1915*cfb92d14SAndroid Build Coastguard Worker def prefer_router_id(self, router_id): 1916*cfb92d14SAndroid Build Coastguard Worker cmd = 'preferrouterid %d' % router_id 1917*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1918*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1919*cfb92d14SAndroid Build Coastguard Worker 1920*cfb92d14SAndroid Build Coastguard Worker def release_router_id(self, router_id): 1921*cfb92d14SAndroid Build Coastguard Worker cmd = 'releaserouterid %d' % router_id 1922*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1923*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1924*cfb92d14SAndroid Build Coastguard Worker 1925*cfb92d14SAndroid Build Coastguard Worker def get_state(self): 1926*cfb92d14SAndroid Build Coastguard Worker states = [r'detached', r'child', r'router', r'leader', r'disabled'] 1927*cfb92d14SAndroid Build Coastguard Worker self.send_command('state') 1928*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(states) 1929*cfb92d14SAndroid Build Coastguard Worker 1930*cfb92d14SAndroid Build Coastguard Worker def set_state(self, state): 1931*cfb92d14SAndroid Build Coastguard Worker cmd = 'state %s' % state 1932*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1933*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1934*cfb92d14SAndroid Build Coastguard Worker 1935*cfb92d14SAndroid Build Coastguard Worker def get_ephemeral_key_state(self): 1936*cfb92d14SAndroid Build Coastguard Worker cmd = 'ba ephemeralkey' 1937*cfb92d14SAndroid Build Coastguard Worker states = [r'inactive', r'active'] 1938*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1939*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(states) 1940*cfb92d14SAndroid Build Coastguard Worker 1941*cfb92d14SAndroid Build Coastguard Worker def get_timeout(self): 1942*cfb92d14SAndroid Build Coastguard Worker self.send_command('childtimeout') 1943*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 1944*cfb92d14SAndroid Build Coastguard Worker 1945*cfb92d14SAndroid Build Coastguard Worker def set_timeout(self, timeout): 1946*cfb92d14SAndroid Build Coastguard Worker cmd = 'childtimeout %d' % timeout 1947*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1948*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1949*cfb92d14SAndroid Build Coastguard Worker 1950*cfb92d14SAndroid Build Coastguard Worker def set_max_children(self, number): 1951*cfb92d14SAndroid Build Coastguard Worker cmd = 'childmax %d' % number 1952*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1953*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1954*cfb92d14SAndroid Build Coastguard Worker 1955*cfb92d14SAndroid Build Coastguard Worker def get_weight(self): 1956*cfb92d14SAndroid Build Coastguard Worker self.send_command('leaderweight') 1957*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 1958*cfb92d14SAndroid Build Coastguard Worker 1959*cfb92d14SAndroid Build Coastguard Worker def set_weight(self, weight): 1960*cfb92d14SAndroid Build Coastguard Worker cmd = 'leaderweight %d' % weight 1961*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1962*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1963*cfb92d14SAndroid Build Coastguard Worker 1964*cfb92d14SAndroid Build Coastguard Worker def add_ipaddr(self, ipaddr): 1965*cfb92d14SAndroid Build Coastguard Worker cmd = 'ipaddr add %s' % ipaddr 1966*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1967*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1968*cfb92d14SAndroid Build Coastguard Worker 1969*cfb92d14SAndroid Build Coastguard Worker def del_ipaddr(self, ipaddr): 1970*cfb92d14SAndroid Build Coastguard Worker cmd = 'ipaddr del %s' % ipaddr 1971*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1972*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1973*cfb92d14SAndroid Build Coastguard Worker 1974*cfb92d14SAndroid Build Coastguard Worker def add_ipmaddr(self, ipmaddr): 1975*cfb92d14SAndroid Build Coastguard Worker cmd = 'ipmaddr add %s' % ipmaddr 1976*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1977*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1978*cfb92d14SAndroid Build Coastguard Worker 1979*cfb92d14SAndroid Build Coastguard Worker def del_ipmaddr(self, ipmaddr): 1980*cfb92d14SAndroid Build Coastguard Worker cmd = 'ipmaddr del %s' % ipmaddr 1981*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 1982*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 1983*cfb92d14SAndroid Build Coastguard Worker 1984*cfb92d14SAndroid Build Coastguard Worker def get_addrs(self, verbose=False): 1985*cfb92d14SAndroid Build Coastguard Worker self.send_command('ipaddr' + (' -v' if verbose else '')) 1986*cfb92d14SAndroid Build Coastguard Worker 1987*cfb92d14SAndroid Build Coastguard Worker return self._expect_results(r'\S+(:\S*)+') 1988*cfb92d14SAndroid Build Coastguard Worker 1989*cfb92d14SAndroid Build Coastguard Worker def get_mleid(self): 1990*cfb92d14SAndroid Build Coastguard Worker self.send_command('ipaddr mleid') 1991*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\S+(:\S*)+') 1992*cfb92d14SAndroid Build Coastguard Worker 1993*cfb92d14SAndroid Build Coastguard Worker def get_linklocal(self): 1994*cfb92d14SAndroid Build Coastguard Worker self.send_command('ipaddr linklocal') 1995*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\S+(:\S*)+') 1996*cfb92d14SAndroid Build Coastguard Worker 1997*cfb92d14SAndroid Build Coastguard Worker def get_rloc(self): 1998*cfb92d14SAndroid Build Coastguard Worker self.send_command('ipaddr rloc') 1999*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\S+(:\S*)+') 2000*cfb92d14SAndroid Build Coastguard Worker 2001*cfb92d14SAndroid Build Coastguard Worker def get_addr(self, prefix): 2002*cfb92d14SAndroid Build Coastguard Worker network = ipaddress.ip_network(u'%s' % str(prefix)) 2003*cfb92d14SAndroid Build Coastguard Worker addrs = self.get_addrs() 2004*cfb92d14SAndroid Build Coastguard Worker 2005*cfb92d14SAndroid Build Coastguard Worker for addr in addrs: 2006*cfb92d14SAndroid Build Coastguard Worker if isinstance(addr, bytearray): 2007*cfb92d14SAndroid Build Coastguard Worker addr = bytes(addr) 2008*cfb92d14SAndroid Build Coastguard Worker ipv6_address = ipaddress.ip_address(addr) 2009*cfb92d14SAndroid Build Coastguard Worker if ipv6_address in network: 2010*cfb92d14SAndroid Build Coastguard Worker return ipv6_address.exploded 2011*cfb92d14SAndroid Build Coastguard Worker 2012*cfb92d14SAndroid Build Coastguard Worker return None 2013*cfb92d14SAndroid Build Coastguard Worker 2014*cfb92d14SAndroid Build Coastguard Worker def has_ipaddr(self, address): 2015*cfb92d14SAndroid Build Coastguard Worker ipaddr = ipaddress.ip_address(address) 2016*cfb92d14SAndroid Build Coastguard Worker ipaddrs = self.get_addrs() 2017*cfb92d14SAndroid Build Coastguard Worker for addr in ipaddrs: 2018*cfb92d14SAndroid Build Coastguard Worker if isinstance(addr, bytearray): 2019*cfb92d14SAndroid Build Coastguard Worker addr = bytes(addr) 2020*cfb92d14SAndroid Build Coastguard Worker if ipaddress.ip_address(addr) == ipaddr: 2021*cfb92d14SAndroid Build Coastguard Worker return True 2022*cfb92d14SAndroid Build Coastguard Worker return False 2023*cfb92d14SAndroid Build Coastguard Worker 2024*cfb92d14SAndroid Build Coastguard Worker def get_ipmaddrs(self): 2025*cfb92d14SAndroid Build Coastguard Worker self.send_command('ipmaddr') 2026*cfb92d14SAndroid Build Coastguard Worker return self._expect_results(r'\S+(:\S*)+') 2027*cfb92d14SAndroid Build Coastguard Worker 2028*cfb92d14SAndroid Build Coastguard Worker def has_ipmaddr(self, address): 2029*cfb92d14SAndroid Build Coastguard Worker ipmaddr = ipaddress.ip_address(address) 2030*cfb92d14SAndroid Build Coastguard Worker ipmaddrs = self.get_ipmaddrs() 2031*cfb92d14SAndroid Build Coastguard Worker for addr in ipmaddrs: 2032*cfb92d14SAndroid Build Coastguard Worker if isinstance(addr, bytearray): 2033*cfb92d14SAndroid Build Coastguard Worker addr = bytes(addr) 2034*cfb92d14SAndroid Build Coastguard Worker if ipaddress.ip_address(addr) == ipmaddr: 2035*cfb92d14SAndroid Build Coastguard Worker return True 2036*cfb92d14SAndroid Build Coastguard Worker return False 2037*cfb92d14SAndroid Build Coastguard Worker 2038*cfb92d14SAndroid Build Coastguard Worker def get_addr_leader_aloc(self): 2039*cfb92d14SAndroid Build Coastguard Worker addrs = self.get_addrs() 2040*cfb92d14SAndroid Build Coastguard Worker for addr in addrs: 2041*cfb92d14SAndroid Build Coastguard Worker segs = addr.split(':') 2042*cfb92d14SAndroid Build Coastguard Worker if (segs[4] == '0' and segs[5] == 'ff' and segs[6] == 'fe00' and segs[7] == 'fc00'): 2043*cfb92d14SAndroid Build Coastguard Worker return addr 2044*cfb92d14SAndroid Build Coastguard Worker return None 2045*cfb92d14SAndroid Build Coastguard Worker 2046*cfb92d14SAndroid Build Coastguard Worker def get_mleid_iid(self): 2047*cfb92d14SAndroid Build Coastguard Worker ml_eid = IPv6Address(self.get_mleid()) 2048*cfb92d14SAndroid Build Coastguard Worker return ml_eid.packed[8:].hex() 2049*cfb92d14SAndroid Build Coastguard Worker 2050*cfb92d14SAndroid Build Coastguard Worker def get_eidcaches(self): 2051*cfb92d14SAndroid Build Coastguard Worker eidcaches = [] 2052*cfb92d14SAndroid Build Coastguard Worker self.send_command('eidcache') 2053*cfb92d14SAndroid Build Coastguard Worker for line in self._expect_results(r'([a-fA-F0-9\:]+) ([a-fA-F0-9]+)'): 2054*cfb92d14SAndroid Build Coastguard Worker eidcaches.append(line.split()) 2055*cfb92d14SAndroid Build Coastguard Worker 2056*cfb92d14SAndroid Build Coastguard Worker return eidcaches 2057*cfb92d14SAndroid Build Coastguard Worker 2058*cfb92d14SAndroid Build Coastguard Worker def add_service(self, enterpriseNumber, serviceData, serverData): 2059*cfb92d14SAndroid Build Coastguard Worker cmd = 'service add %s %s %s' % ( 2060*cfb92d14SAndroid Build Coastguard Worker enterpriseNumber, 2061*cfb92d14SAndroid Build Coastguard Worker serviceData, 2062*cfb92d14SAndroid Build Coastguard Worker serverData, 2063*cfb92d14SAndroid Build Coastguard Worker ) 2064*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2065*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2066*cfb92d14SAndroid Build Coastguard Worker 2067*cfb92d14SAndroid Build Coastguard Worker def remove_service(self, enterpriseNumber, serviceData): 2068*cfb92d14SAndroid Build Coastguard Worker cmd = 'service remove %s %s' % (enterpriseNumber, serviceData) 2069*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2070*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2071*cfb92d14SAndroid Build Coastguard Worker 2072*cfb92d14SAndroid Build Coastguard Worker def get_child_table(self) -> Dict[int, Dict[str, Any]]: 2073*cfb92d14SAndroid Build Coastguard Worker """Get the table of attached children.""" 2074*cfb92d14SAndroid Build Coastguard Worker cmd = 'child table' 2075*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2076*cfb92d14SAndroid Build Coastguard Worker output = self._expect_command_output() 2077*cfb92d14SAndroid Build Coastguard Worker 2078*cfb92d14SAndroid Build Coastguard Worker # 2079*cfb92d14SAndroid Build Coastguard Worker # Example output: 2080*cfb92d14SAndroid Build Coastguard Worker # | ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt|Suprvsn| Extended MAC | 2081*cfb92d14SAndroid Build Coastguard Worker # +-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+-------+------------------+ 2082*cfb92d14SAndroid Build Coastguard Worker # | 1 | 0xc801 | 240 | 24 | 3 | 131 |1|0|0| 3| 0 | 0 | 129 | 4ecede68435358ac | 2083*cfb92d14SAndroid Build Coastguard Worker # | 2 | 0xc802 | 240 | 2 | 3 | 131 |0|0|0| 3| 1 | 0 | 0 | a672a601d2ce37d8 | 2084*cfb92d14SAndroid Build Coastguard Worker # Done 2085*cfb92d14SAndroid Build Coastguard Worker # 2086*cfb92d14SAndroid Build Coastguard Worker 2087*cfb92d14SAndroid Build Coastguard Worker headers = self.__split_table_row(output[0]) 2088*cfb92d14SAndroid Build Coastguard Worker 2089*cfb92d14SAndroid Build Coastguard Worker table = {} 2090*cfb92d14SAndroid Build Coastguard Worker for line in output[2:]: 2091*cfb92d14SAndroid Build Coastguard Worker line = line.strip() 2092*cfb92d14SAndroid Build Coastguard Worker if not line: 2093*cfb92d14SAndroid Build Coastguard Worker continue 2094*cfb92d14SAndroid Build Coastguard Worker 2095*cfb92d14SAndroid Build Coastguard Worker fields = self.__split_table_row(line) 2096*cfb92d14SAndroid Build Coastguard Worker col = lambda colname: self.__get_table_col(colname, headers, fields) 2097*cfb92d14SAndroid Build Coastguard Worker 2098*cfb92d14SAndroid Build Coastguard Worker id = int(col("ID")) 2099*cfb92d14SAndroid Build Coastguard Worker r, d, n = int(col("R")), int(col("D")), int(col("N")) 2100*cfb92d14SAndroid Build Coastguard Worker mode = f'{"r" if r else ""}{"d" if d else ""}{"n" if n else ""}' 2101*cfb92d14SAndroid Build Coastguard Worker 2102*cfb92d14SAndroid Build Coastguard Worker table[int(id)] = { 2103*cfb92d14SAndroid Build Coastguard Worker 'id': int(id), 2104*cfb92d14SAndroid Build Coastguard Worker 'rloc16': int(col('RLOC16'), 16), 2105*cfb92d14SAndroid Build Coastguard Worker 'timeout': int(col('Timeout')), 2106*cfb92d14SAndroid Build Coastguard Worker 'age': int(col('Age')), 2107*cfb92d14SAndroid Build Coastguard Worker 'lq_in': int(col('LQ In')), 2108*cfb92d14SAndroid Build Coastguard Worker 'c_vn': int(col('C_VN')), 2109*cfb92d14SAndroid Build Coastguard Worker 'mode': mode, 2110*cfb92d14SAndroid Build Coastguard Worker 'extaddr': col('Extended MAC'), 2111*cfb92d14SAndroid Build Coastguard Worker 'ver': int(col('Ver')), 2112*cfb92d14SAndroid Build Coastguard Worker 'csl': bool(int(col('CSL'))), 2113*cfb92d14SAndroid Build Coastguard Worker 'qmsgcnt': int(col('QMsgCnt')), 2114*cfb92d14SAndroid Build Coastguard Worker 'suprvsn': int(col('Suprvsn')) 2115*cfb92d14SAndroid Build Coastguard Worker } 2116*cfb92d14SAndroid Build Coastguard Worker 2117*cfb92d14SAndroid Build Coastguard Worker return table 2118*cfb92d14SAndroid Build Coastguard Worker 2119*cfb92d14SAndroid Build Coastguard Worker def __split_table_row(self, row: str) -> List[str]: 2120*cfb92d14SAndroid Build Coastguard Worker if not (row.startswith('|') and row.endswith('|')): 2121*cfb92d14SAndroid Build Coastguard Worker raise ValueError(row) 2122*cfb92d14SAndroid Build Coastguard Worker 2123*cfb92d14SAndroid Build Coastguard Worker fields = row.split('|') 2124*cfb92d14SAndroid Build Coastguard Worker fields = [x.strip() for x in fields[1:-1]] 2125*cfb92d14SAndroid Build Coastguard Worker return fields 2126*cfb92d14SAndroid Build Coastguard Worker 2127*cfb92d14SAndroid Build Coastguard Worker def __get_table_col(self, colname: str, headers: List[str], fields: List[str]) -> str: 2128*cfb92d14SAndroid Build Coastguard Worker return fields[headers.index(colname)] 2129*cfb92d14SAndroid Build Coastguard Worker 2130*cfb92d14SAndroid Build Coastguard Worker def __getOmrAddress(self): 2131*cfb92d14SAndroid Build Coastguard Worker prefixes = [prefix.split('::')[0] for prefix in self.get_prefixes()] 2132*cfb92d14SAndroid Build Coastguard Worker omr_addrs = [] 2133*cfb92d14SAndroid Build Coastguard Worker for addr in self.get_addrs(): 2134*cfb92d14SAndroid Build Coastguard Worker for prefix in prefixes: 2135*cfb92d14SAndroid Build Coastguard Worker if (addr.startswith(prefix)) and (addr != self.__getDua()): 2136*cfb92d14SAndroid Build Coastguard Worker omr_addrs.append(addr) 2137*cfb92d14SAndroid Build Coastguard Worker break 2138*cfb92d14SAndroid Build Coastguard Worker 2139*cfb92d14SAndroid Build Coastguard Worker return omr_addrs 2140*cfb92d14SAndroid Build Coastguard Worker 2141*cfb92d14SAndroid Build Coastguard Worker def __getLinkLocalAddress(self): 2142*cfb92d14SAndroid Build Coastguard Worker for ip6Addr in self.get_addrs(): 2143*cfb92d14SAndroid Build Coastguard Worker if re.match(config.LINK_LOCAL_REGEX_PATTERN, ip6Addr, re.I): 2144*cfb92d14SAndroid Build Coastguard Worker return ip6Addr 2145*cfb92d14SAndroid Build Coastguard Worker 2146*cfb92d14SAndroid Build Coastguard Worker return None 2147*cfb92d14SAndroid Build Coastguard Worker 2148*cfb92d14SAndroid Build Coastguard Worker def __getGlobalAddress(self): 2149*cfb92d14SAndroid Build Coastguard Worker global_address = [] 2150*cfb92d14SAndroid Build Coastguard Worker for ip6Addr in self.get_addrs(): 2151*cfb92d14SAndroid Build Coastguard Worker if ((not re.match(config.LINK_LOCAL_REGEX_PATTERN, ip6Addr, re.I)) and 2152*cfb92d14SAndroid Build Coastguard Worker (not re.match(config.MESH_LOCAL_PREFIX_REGEX_PATTERN, ip6Addr, re.I)) and 2153*cfb92d14SAndroid Build Coastguard Worker (not re.match(config.ROUTING_LOCATOR_REGEX_PATTERN, ip6Addr, re.I))): 2154*cfb92d14SAndroid Build Coastguard Worker global_address.append(ip6Addr) 2155*cfb92d14SAndroid Build Coastguard Worker 2156*cfb92d14SAndroid Build Coastguard Worker return global_address 2157*cfb92d14SAndroid Build Coastguard Worker 2158*cfb92d14SAndroid Build Coastguard Worker def __getRloc(self): 2159*cfb92d14SAndroid Build Coastguard Worker for ip6Addr in self.get_addrs(): 2160*cfb92d14SAndroid Build Coastguard Worker if (re.match(config.MESH_LOCAL_PREFIX_REGEX_PATTERN, ip6Addr, re.I) and 2161*cfb92d14SAndroid Build Coastguard Worker re.match(config.ROUTING_LOCATOR_REGEX_PATTERN, ip6Addr, re.I) and 2162*cfb92d14SAndroid Build Coastguard Worker not (re.match(config.ALOC_FLAG_REGEX_PATTERN, ip6Addr, re.I))): 2163*cfb92d14SAndroid Build Coastguard Worker return ip6Addr 2164*cfb92d14SAndroid Build Coastguard Worker return None 2165*cfb92d14SAndroid Build Coastguard Worker 2166*cfb92d14SAndroid Build Coastguard Worker def __getAloc(self): 2167*cfb92d14SAndroid Build Coastguard Worker aloc = [] 2168*cfb92d14SAndroid Build Coastguard Worker for ip6Addr in self.get_addrs(): 2169*cfb92d14SAndroid Build Coastguard Worker if (re.match(config.MESH_LOCAL_PREFIX_REGEX_PATTERN, ip6Addr, re.I) and 2170*cfb92d14SAndroid Build Coastguard Worker re.match(config.ROUTING_LOCATOR_REGEX_PATTERN, ip6Addr, re.I) and 2171*cfb92d14SAndroid Build Coastguard Worker re.match(config.ALOC_FLAG_REGEX_PATTERN, ip6Addr, re.I)): 2172*cfb92d14SAndroid Build Coastguard Worker aloc.append(ip6Addr) 2173*cfb92d14SAndroid Build Coastguard Worker 2174*cfb92d14SAndroid Build Coastguard Worker return aloc 2175*cfb92d14SAndroid Build Coastguard Worker 2176*cfb92d14SAndroid Build Coastguard Worker def __getMleid(self): 2177*cfb92d14SAndroid Build Coastguard Worker for ip6Addr in self.get_addrs(): 2178*cfb92d14SAndroid Build Coastguard Worker if re.match(config.MESH_LOCAL_PREFIX_REGEX_PATTERN, ip6Addr, 2179*cfb92d14SAndroid Build Coastguard Worker re.I) and not (re.match(config.ROUTING_LOCATOR_REGEX_PATTERN, ip6Addr, re.I)): 2180*cfb92d14SAndroid Build Coastguard Worker return ip6Addr 2181*cfb92d14SAndroid Build Coastguard Worker 2182*cfb92d14SAndroid Build Coastguard Worker return None 2183*cfb92d14SAndroid Build Coastguard Worker 2184*cfb92d14SAndroid Build Coastguard Worker def __getDua(self) -> Optional[str]: 2185*cfb92d14SAndroid Build Coastguard Worker for ip6Addr in self.get_addrs(): 2186*cfb92d14SAndroid Build Coastguard Worker if re.match(config.DOMAIN_PREFIX_REGEX_PATTERN, ip6Addr, re.I): 2187*cfb92d14SAndroid Build Coastguard Worker return ip6Addr 2188*cfb92d14SAndroid Build Coastguard Worker 2189*cfb92d14SAndroid Build Coastguard Worker return None 2190*cfb92d14SAndroid Build Coastguard Worker 2191*cfb92d14SAndroid Build Coastguard Worker def get_ip6_address_by_prefix(self, prefix: Union[str, IPv6Network]) -> List[IPv6Address]: 2192*cfb92d14SAndroid Build Coastguard Worker """Get addresses matched with given prefix. 2193*cfb92d14SAndroid Build Coastguard Worker 2194*cfb92d14SAndroid Build Coastguard Worker Args: 2195*cfb92d14SAndroid Build Coastguard Worker prefix: the prefix to match against. 2196*cfb92d14SAndroid Build Coastguard Worker Can be either a string or ipaddress.IPv6Network. 2197*cfb92d14SAndroid Build Coastguard Worker 2198*cfb92d14SAndroid Build Coastguard Worker Returns: 2199*cfb92d14SAndroid Build Coastguard Worker The IPv6 address list. 2200*cfb92d14SAndroid Build Coastguard Worker """ 2201*cfb92d14SAndroid Build Coastguard Worker if isinstance(prefix, str): 2202*cfb92d14SAndroid Build Coastguard Worker prefix = IPv6Network(prefix) 2203*cfb92d14SAndroid Build Coastguard Worker addrs = map(IPv6Address, self.get_addrs()) 2204*cfb92d14SAndroid Build Coastguard Worker 2205*cfb92d14SAndroid Build Coastguard Worker return [addr for addr in addrs if addr in prefix] 2206*cfb92d14SAndroid Build Coastguard Worker 2207*cfb92d14SAndroid Build Coastguard Worker def get_ip6_address(self, address_type): 2208*cfb92d14SAndroid Build Coastguard Worker """Get specific type of IPv6 address configured on thread device. 2209*cfb92d14SAndroid Build Coastguard Worker 2210*cfb92d14SAndroid Build Coastguard Worker Args: 2211*cfb92d14SAndroid Build Coastguard Worker address_type: the config.ADDRESS_TYPE type of IPv6 address. 2212*cfb92d14SAndroid Build Coastguard Worker 2213*cfb92d14SAndroid Build Coastguard Worker Returns: 2214*cfb92d14SAndroid Build Coastguard Worker IPv6 address string. 2215*cfb92d14SAndroid Build Coastguard Worker """ 2216*cfb92d14SAndroid Build Coastguard Worker if address_type == config.ADDRESS_TYPE.LINK_LOCAL: 2217*cfb92d14SAndroid Build Coastguard Worker return self.__getLinkLocalAddress() 2218*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.GLOBAL: 2219*cfb92d14SAndroid Build Coastguard Worker return self.__getGlobalAddress() 2220*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.RLOC: 2221*cfb92d14SAndroid Build Coastguard Worker return self.__getRloc() 2222*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.ALOC: 2223*cfb92d14SAndroid Build Coastguard Worker return self.__getAloc() 2224*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.ML_EID: 2225*cfb92d14SAndroid Build Coastguard Worker return self.__getMleid() 2226*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.DUA: 2227*cfb92d14SAndroid Build Coastguard Worker return self.__getDua() 2228*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.BACKBONE_GUA: 2229*cfb92d14SAndroid Build Coastguard Worker return self._getBackboneGua() 2230*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.OMR: 2231*cfb92d14SAndroid Build Coastguard Worker return self.__getOmrAddress() 2232*cfb92d14SAndroid Build Coastguard Worker else: 2233*cfb92d14SAndroid Build Coastguard Worker return None 2234*cfb92d14SAndroid Build Coastguard Worker 2235*cfb92d14SAndroid Build Coastguard Worker def get_context_reuse_delay(self): 2236*cfb92d14SAndroid Build Coastguard Worker self.send_command('contextreusedelay') 2237*cfb92d14SAndroid Build Coastguard Worker return self._expect_result(r'\d+') 2238*cfb92d14SAndroid Build Coastguard Worker 2239*cfb92d14SAndroid Build Coastguard Worker def set_context_reuse_delay(self, delay): 2240*cfb92d14SAndroid Build Coastguard Worker cmd = 'contextreusedelay %d' % delay 2241*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2242*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2243*cfb92d14SAndroid Build Coastguard Worker 2244*cfb92d14SAndroid Build Coastguard Worker def add_prefix(self, prefix, flags='paosr', prf='med'): 2245*cfb92d14SAndroid Build Coastguard Worker cmd = 'prefix add %s %s %s' % (prefix, flags, prf) 2246*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2247*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2248*cfb92d14SAndroid Build Coastguard Worker 2249*cfb92d14SAndroid Build Coastguard Worker def remove_prefix(self, prefix): 2250*cfb92d14SAndroid Build Coastguard Worker cmd = 'prefix remove %s' % prefix 2251*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2252*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2253*cfb92d14SAndroid Build Coastguard Worker 2254*cfb92d14SAndroid Build Coastguard Worker # 2255*cfb92d14SAndroid Build Coastguard Worker # BR commands 2256*cfb92d14SAndroid Build Coastguard Worker # 2257*cfb92d14SAndroid Build Coastguard Worker def enable_br(self): 2258*cfb92d14SAndroid Build Coastguard Worker self.send_command('br enable') 2259*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2260*cfb92d14SAndroid Build Coastguard Worker 2261*cfb92d14SAndroid Build Coastguard Worker def disable_br(self): 2262*cfb92d14SAndroid Build Coastguard Worker self.send_command('br disable') 2263*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2264*cfb92d14SAndroid Build Coastguard Worker 2265*cfb92d14SAndroid Build Coastguard Worker def get_br_omr_prefix(self): 2266*cfb92d14SAndroid Build Coastguard Worker cmd = 'br omrprefix local' 2267*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2268*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0] 2269*cfb92d14SAndroid Build Coastguard Worker 2270*cfb92d14SAndroid Build Coastguard Worker def get_br_peers(self) -> List[str]: 2271*cfb92d14SAndroid Build Coastguard Worker # Example output of `br peers` command: 2272*cfb92d14SAndroid Build Coastguard Worker # rloc16:0xa800 age:00:00:50 2273*cfb92d14SAndroid Build Coastguard Worker # rloc16:0x6800 age:00:00:51 2274*cfb92d14SAndroid Build Coastguard Worker # Done 2275*cfb92d14SAndroid Build Coastguard Worker self.send_command('br peers') 2276*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output() 2277*cfb92d14SAndroid Build Coastguard Worker 2278*cfb92d14SAndroid Build Coastguard Worker def get_br_peers_rloc16s(self) -> List[int]: 2279*cfb92d14SAndroid Build Coastguard Worker """parse `br peers` output and return the list of RLOC16s""" 2280*cfb92d14SAndroid Build Coastguard Worker return [ 2281*cfb92d14SAndroid Build Coastguard Worker int(pair.split(':')[1], 16) 2282*cfb92d14SAndroid Build Coastguard Worker for line in self.get_br_peers() 2283*cfb92d14SAndroid Build Coastguard Worker for pair in line.split() 2284*cfb92d14SAndroid Build Coastguard Worker if pair.split(':')[0] == 'rloc16' 2285*cfb92d14SAndroid Build Coastguard Worker ] 2286*cfb92d14SAndroid Build Coastguard Worker 2287*cfb92d14SAndroid Build Coastguard Worker def get_br_routers(self) -> List[str]: 2288*cfb92d14SAndroid Build Coastguard Worker # Example output of `br routers` command: 2289*cfb92d14SAndroid Build Coastguard Worker # fe80:0:0:0:42:acff:fe14:3 (M:0 O:0 Stub:1) ms-since-rx:144160 reachable:yes age:00:17:36 (peer BR) 2290*cfb92d14SAndroid Build Coastguard Worker # fe80:0:0:0:42:acff:fe14:2 (M:0 O:0 Stub:1) ms-since-rx:45179 reachable:yes age:00:17:36 2291*cfb92d14SAndroid Build Coastguard Worker # Done 2292*cfb92d14SAndroid Build Coastguard Worker self.send_command('br routers') 2293*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output() 2294*cfb92d14SAndroid Build Coastguard Worker 2295*cfb92d14SAndroid Build Coastguard Worker def get_br_routers_ip_addresses(self) -> List[IPv6Address]: 2296*cfb92d14SAndroid Build Coastguard Worker """parse `br routers` output and return the list of IPv6 addresses""" 2297*cfb92d14SAndroid Build Coastguard Worker return [IPv6Address(line.split()[0]) for line in self.get_br_routers()] 2298*cfb92d14SAndroid Build Coastguard Worker 2299*cfb92d14SAndroid Build Coastguard Worker def get_netdata_omr_prefixes(self): 2300*cfb92d14SAndroid Build Coastguard Worker omr_prefixes = [] 2301*cfb92d14SAndroid Build Coastguard Worker for prefix in self.get_prefixes(): 2302*cfb92d14SAndroid Build Coastguard Worker prefix, flags = prefix.split()[:2] 2303*cfb92d14SAndroid Build Coastguard Worker if 'a' in flags and 'o' in flags and 's' in flags and 'D' not in flags: 2304*cfb92d14SAndroid Build Coastguard Worker omr_prefixes.append(prefix) 2305*cfb92d14SAndroid Build Coastguard Worker 2306*cfb92d14SAndroid Build Coastguard Worker return omr_prefixes 2307*cfb92d14SAndroid Build Coastguard Worker 2308*cfb92d14SAndroid Build Coastguard Worker def get_br_on_link_prefix(self): 2309*cfb92d14SAndroid Build Coastguard Worker cmd = 'br onlinkprefix local' 2310*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2311*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0] 2312*cfb92d14SAndroid Build Coastguard Worker 2313*cfb92d14SAndroid Build Coastguard Worker def get_netdata_non_nat64_routes(self): 2314*cfb92d14SAndroid Build Coastguard Worker nat64_routes = [] 2315*cfb92d14SAndroid Build Coastguard Worker routes = self.get_routes() 2316*cfb92d14SAndroid Build Coastguard Worker for route in routes: 2317*cfb92d14SAndroid Build Coastguard Worker if 'n' not in route.split(' ')[1]: 2318*cfb92d14SAndroid Build Coastguard Worker nat64_routes.append(route.split(' ')[0]) 2319*cfb92d14SAndroid Build Coastguard Worker return nat64_routes 2320*cfb92d14SAndroid Build Coastguard Worker 2321*cfb92d14SAndroid Build Coastguard Worker def get_netdata_nat64_routes(self): 2322*cfb92d14SAndroid Build Coastguard Worker nat64_routes = [] 2323*cfb92d14SAndroid Build Coastguard Worker routes = self.get_routes() 2324*cfb92d14SAndroid Build Coastguard Worker for route in routes: 2325*cfb92d14SAndroid Build Coastguard Worker if 'n' in route.split(' ')[1]: 2326*cfb92d14SAndroid Build Coastguard Worker nat64_routes.append(route.split(' ')[0]) 2327*cfb92d14SAndroid Build Coastguard Worker return nat64_routes 2328*cfb92d14SAndroid Build Coastguard Worker 2329*cfb92d14SAndroid Build Coastguard Worker def get_br_nat64_prefix(self): 2330*cfb92d14SAndroid Build Coastguard Worker cmd = 'br nat64prefix local' 2331*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2332*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0] 2333*cfb92d14SAndroid Build Coastguard Worker 2334*cfb92d14SAndroid Build Coastguard Worker def get_br_favored_nat64_prefix(self): 2335*cfb92d14SAndroid Build Coastguard Worker cmd = 'br nat64prefix favored' 2336*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2337*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output()[0].split(' ')[0] 2338*cfb92d14SAndroid Build Coastguard Worker 2339*cfb92d14SAndroid Build Coastguard Worker def enable_nat64(self): 2340*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'nat64 enable') 2341*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2342*cfb92d14SAndroid Build Coastguard Worker 2343*cfb92d14SAndroid Build Coastguard Worker def disable_nat64(self): 2344*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'nat64 disable') 2345*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2346*cfb92d14SAndroid Build Coastguard Worker 2347*cfb92d14SAndroid Build Coastguard Worker def get_nat64_state(self): 2348*cfb92d14SAndroid Build Coastguard Worker self.send_command('nat64 state') 2349*cfb92d14SAndroid Build Coastguard Worker res = {} 2350*cfb92d14SAndroid Build Coastguard Worker for line in self._expect_command_output(): 2351*cfb92d14SAndroid Build Coastguard Worker state = line.split(':') 2352*cfb92d14SAndroid Build Coastguard Worker res[state[0].strip()] = state[1].strip() 2353*cfb92d14SAndroid Build Coastguard Worker return res 2354*cfb92d14SAndroid Build Coastguard Worker 2355*cfb92d14SAndroid Build Coastguard Worker def get_nat64_mappings(self): 2356*cfb92d14SAndroid Build Coastguard Worker cmd = 'nat64 mappings' 2357*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2358*cfb92d14SAndroid Build Coastguard Worker result = self._expect_command_output() 2359*cfb92d14SAndroid Build Coastguard Worker session = None 2360*cfb92d14SAndroid Build Coastguard Worker session_counters = None 2361*cfb92d14SAndroid Build Coastguard Worker sessions = [] 2362*cfb92d14SAndroid Build Coastguard Worker 2363*cfb92d14SAndroid Build Coastguard Worker for line in result: 2364*cfb92d14SAndroid Build Coastguard Worker m = re.match( 2365*cfb92d14SAndroid Build Coastguard Worker r'\|\s+([a-f0-9]+)\s+\|\s+(.+)\s+\|\s+(.+)\s+\|\s+(\d+)s\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|', 2366*cfb92d14SAndroid Build Coastguard Worker line) 2367*cfb92d14SAndroid Build Coastguard Worker if m: 2368*cfb92d14SAndroid Build Coastguard Worker groups = m.groups() 2369*cfb92d14SAndroid Build Coastguard Worker if session: 2370*cfb92d14SAndroid Build Coastguard Worker session['counters'] = session_counters 2371*cfb92d14SAndroid Build Coastguard Worker sessions.append(session) 2372*cfb92d14SAndroid Build Coastguard Worker session = { 2373*cfb92d14SAndroid Build Coastguard Worker 'id': groups[0], 2374*cfb92d14SAndroid Build Coastguard Worker 'ip6': groups[1], 2375*cfb92d14SAndroid Build Coastguard Worker 'ip4': groups[2], 2376*cfb92d14SAndroid Build Coastguard Worker 'expiry': int(groups[3]), 2377*cfb92d14SAndroid Build Coastguard Worker } 2378*cfb92d14SAndroid Build Coastguard Worker session_counters = {} 2379*cfb92d14SAndroid Build Coastguard Worker session_counters['total'] = { 2380*cfb92d14SAndroid Build Coastguard Worker '4to6': { 2381*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[4]), 2382*cfb92d14SAndroid Build Coastguard Worker 'bytes': int(groups[5]), 2383*cfb92d14SAndroid Build Coastguard Worker }, 2384*cfb92d14SAndroid Build Coastguard Worker '6to4': { 2385*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[6]), 2386*cfb92d14SAndroid Build Coastguard Worker 'bytes': int(groups[7]), 2387*cfb92d14SAndroid Build Coastguard Worker }, 2388*cfb92d14SAndroid Build Coastguard Worker } 2389*cfb92d14SAndroid Build Coastguard Worker continue 2390*cfb92d14SAndroid Build Coastguard Worker if not session: 2391*cfb92d14SAndroid Build Coastguard Worker continue 2392*cfb92d14SAndroid Build Coastguard Worker m = re.match(r'\|\s+\|\s+(.+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|', line) 2393*cfb92d14SAndroid Build Coastguard Worker if m: 2394*cfb92d14SAndroid Build Coastguard Worker groups = m.groups() 2395*cfb92d14SAndroid Build Coastguard Worker session_counters[groups[0]] = { 2396*cfb92d14SAndroid Build Coastguard Worker '4to6': { 2397*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[1]), 2398*cfb92d14SAndroid Build Coastguard Worker 'bytes': int(groups[2]), 2399*cfb92d14SAndroid Build Coastguard Worker }, 2400*cfb92d14SAndroid Build Coastguard Worker '6to4': { 2401*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[3]), 2402*cfb92d14SAndroid Build Coastguard Worker 'bytes': int(groups[4]), 2403*cfb92d14SAndroid Build Coastguard Worker }, 2404*cfb92d14SAndroid Build Coastguard Worker } 2405*cfb92d14SAndroid Build Coastguard Worker if session: 2406*cfb92d14SAndroid Build Coastguard Worker session['counters'] = session_counters 2407*cfb92d14SAndroid Build Coastguard Worker sessions.append(session) 2408*cfb92d14SAndroid Build Coastguard Worker return sessions 2409*cfb92d14SAndroid Build Coastguard Worker 2410*cfb92d14SAndroid Build Coastguard Worker def get_nat64_counters(self): 2411*cfb92d14SAndroid Build Coastguard Worker cmd = 'nat64 counters' 2412*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2413*cfb92d14SAndroid Build Coastguard Worker result = self._expect_command_output() 2414*cfb92d14SAndroid Build Coastguard Worker 2415*cfb92d14SAndroid Build Coastguard Worker protocol_counters = {} 2416*cfb92d14SAndroid Build Coastguard Worker error_counters = {} 2417*cfb92d14SAndroid Build Coastguard Worker for line in result: 2418*cfb92d14SAndroid Build Coastguard Worker m = re.match(r'\|\s+(.+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|', line) 2419*cfb92d14SAndroid Build Coastguard Worker if m: 2420*cfb92d14SAndroid Build Coastguard Worker groups = m.groups() 2421*cfb92d14SAndroid Build Coastguard Worker protocol_counters[groups[0]] = { 2422*cfb92d14SAndroid Build Coastguard Worker '4to6': { 2423*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[1]), 2424*cfb92d14SAndroid Build Coastguard Worker 'bytes': int(groups[2]), 2425*cfb92d14SAndroid Build Coastguard Worker }, 2426*cfb92d14SAndroid Build Coastguard Worker '6to4': { 2427*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[3]), 2428*cfb92d14SAndroid Build Coastguard Worker 'bytes': int(groups[4]), 2429*cfb92d14SAndroid Build Coastguard Worker }, 2430*cfb92d14SAndroid Build Coastguard Worker } 2431*cfb92d14SAndroid Build Coastguard Worker continue 2432*cfb92d14SAndroid Build Coastguard Worker m = re.match(r'\|\s+(.+)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|', line) 2433*cfb92d14SAndroid Build Coastguard Worker if m: 2434*cfb92d14SAndroid Build Coastguard Worker groups = m.groups() 2435*cfb92d14SAndroid Build Coastguard Worker error_counters[groups[0]] = { 2436*cfb92d14SAndroid Build Coastguard Worker '4to6': { 2437*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[1]), 2438*cfb92d14SAndroid Build Coastguard Worker }, 2439*cfb92d14SAndroid Build Coastguard Worker '6to4': { 2440*cfb92d14SAndroid Build Coastguard Worker 'packets': int(groups[2]), 2441*cfb92d14SAndroid Build Coastguard Worker }, 2442*cfb92d14SAndroid Build Coastguard Worker } 2443*cfb92d14SAndroid Build Coastguard Worker continue 2444*cfb92d14SAndroid Build Coastguard Worker return {'protocol': protocol_counters, 'errors': error_counters} 2445*cfb92d14SAndroid Build Coastguard Worker 2446*cfb92d14SAndroid Build Coastguard Worker def get_prefixes(self): 2447*cfb92d14SAndroid Build Coastguard Worker return self.get_netdata()['Prefixes'] 2448*cfb92d14SAndroid Build Coastguard Worker 2449*cfb92d14SAndroid Build Coastguard Worker def get_routes(self): 2450*cfb92d14SAndroid Build Coastguard Worker return self.get_netdata()['Routes'] 2451*cfb92d14SAndroid Build Coastguard Worker 2452*cfb92d14SAndroid Build Coastguard Worker def get_services(self): 2453*cfb92d14SAndroid Build Coastguard Worker netdata = self.netdata_show() 2454*cfb92d14SAndroid Build Coastguard Worker services = [] 2455*cfb92d14SAndroid Build Coastguard Worker services_section = False 2456*cfb92d14SAndroid Build Coastguard Worker 2457*cfb92d14SAndroid Build Coastguard Worker for line in netdata: 2458*cfb92d14SAndroid Build Coastguard Worker if line.startswith('Services:'): 2459*cfb92d14SAndroid Build Coastguard Worker services_section = True 2460*cfb92d14SAndroid Build Coastguard Worker elif line.startswith('Contexts'): 2461*cfb92d14SAndroid Build Coastguard Worker services_section = False 2462*cfb92d14SAndroid Build Coastguard Worker elif services_section: 2463*cfb92d14SAndroid Build Coastguard Worker services.append(line.strip().split(' ')) 2464*cfb92d14SAndroid Build Coastguard Worker return services 2465*cfb92d14SAndroid Build Coastguard Worker 2466*cfb92d14SAndroid Build Coastguard Worker def netdata_show(self): 2467*cfb92d14SAndroid Build Coastguard Worker self.send_command('netdata show') 2468*cfb92d14SAndroid Build Coastguard Worker return self._expect_command_output() 2469*cfb92d14SAndroid Build Coastguard Worker 2470*cfb92d14SAndroid Build Coastguard Worker def get_netdata(self): 2471*cfb92d14SAndroid Build Coastguard Worker raw_netdata = self.netdata_show() 2472*cfb92d14SAndroid Build Coastguard Worker netdata = {'Prefixes': [], 'Routes': [], 'Services': [], 'Contexts': [], 'Commissioning': []} 2473*cfb92d14SAndroid Build Coastguard Worker key_list = ['Prefixes', 'Routes', 'Services', 'Contexts', 'Commissioning'] 2474*cfb92d14SAndroid Build Coastguard Worker key = None 2475*cfb92d14SAndroid Build Coastguard Worker 2476*cfb92d14SAndroid Build Coastguard Worker for i in range(0, len(raw_netdata)): 2477*cfb92d14SAndroid Build Coastguard Worker keys = list(filter(raw_netdata[i].startswith, key_list)) 2478*cfb92d14SAndroid Build Coastguard Worker if keys != []: 2479*cfb92d14SAndroid Build Coastguard Worker key = keys[0] 2480*cfb92d14SAndroid Build Coastguard Worker elif key is not None: 2481*cfb92d14SAndroid Build Coastguard Worker netdata[key].append(raw_netdata[i]) 2482*cfb92d14SAndroid Build Coastguard Worker 2483*cfb92d14SAndroid Build Coastguard Worker return netdata 2484*cfb92d14SAndroid Build Coastguard Worker 2485*cfb92d14SAndroid Build Coastguard Worker def add_route(self, prefix, stable=False, nat64=False, prf='med'): 2486*cfb92d14SAndroid Build Coastguard Worker cmd = 'route add %s ' % prefix 2487*cfb92d14SAndroid Build Coastguard Worker if stable: 2488*cfb92d14SAndroid Build Coastguard Worker cmd += 's' 2489*cfb92d14SAndroid Build Coastguard Worker if nat64: 2490*cfb92d14SAndroid Build Coastguard Worker cmd += 'n' 2491*cfb92d14SAndroid Build Coastguard Worker cmd += ' %s' % prf 2492*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2493*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2494*cfb92d14SAndroid Build Coastguard Worker 2495*cfb92d14SAndroid Build Coastguard Worker def remove_route(self, prefix): 2496*cfb92d14SAndroid Build Coastguard Worker cmd = 'route remove %s' % prefix 2497*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2498*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2499*cfb92d14SAndroid Build Coastguard Worker 2500*cfb92d14SAndroid Build Coastguard Worker def register_netdata(self): 2501*cfb92d14SAndroid Build Coastguard Worker self.send_command('netdata register') 2502*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2503*cfb92d14SAndroid Build Coastguard Worker 2504*cfb92d14SAndroid Build Coastguard Worker def netdata_publish_dnssrp_anycast(self, seqnum): 2505*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'netdata publish dnssrp anycast {seqnum}') 2506*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2507*cfb92d14SAndroid Build Coastguard Worker 2508*cfb92d14SAndroid Build Coastguard Worker def netdata_publish_dnssrp_unicast(self, address, port): 2509*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'netdata publish dnssrp unicast {address} {port}') 2510*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2511*cfb92d14SAndroid Build Coastguard Worker 2512*cfb92d14SAndroid Build Coastguard Worker def netdata_publish_dnssrp_unicast_mleid(self, port): 2513*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'netdata publish dnssrp unicast {port}') 2514*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2515*cfb92d14SAndroid Build Coastguard Worker 2516*cfb92d14SAndroid Build Coastguard Worker def netdata_unpublish_dnssrp(self): 2517*cfb92d14SAndroid Build Coastguard Worker self.send_command('netdata unpublish dnssrp') 2518*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2519*cfb92d14SAndroid Build Coastguard Worker 2520*cfb92d14SAndroid Build Coastguard Worker def netdata_publish_prefix(self, prefix, flags='paosr', prf='med'): 2521*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'netdata publish prefix {prefix} {flags} {prf}') 2522*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2523*cfb92d14SAndroid Build Coastguard Worker 2524*cfb92d14SAndroid Build Coastguard Worker def netdata_publish_route(self, prefix, flags='s', prf='med'): 2525*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'netdata publish route {prefix} {flags} {prf}') 2526*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2527*cfb92d14SAndroid Build Coastguard Worker 2528*cfb92d14SAndroid Build Coastguard Worker def netdata_publish_replace(self, old_prefix, prefix, flags='s', prf='med'): 2529*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'netdata publish replace {old_prefix} {prefix} {flags} {prf}') 2530*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2531*cfb92d14SAndroid Build Coastguard Worker 2532*cfb92d14SAndroid Build Coastguard Worker def netdata_unpublish_prefix(self, prefix): 2533*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'netdata unpublish {prefix}') 2534*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2535*cfb92d14SAndroid Build Coastguard Worker 2536*cfb92d14SAndroid Build Coastguard Worker def send_network_diag_get(self, addr, tlv_types): 2537*cfb92d14SAndroid Build Coastguard Worker self.send_command('networkdiagnostic get %s %s' % (addr, ' '.join([str(t.value) for t in tlv_types]))) 2538*cfb92d14SAndroid Build Coastguard Worker 2539*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 2540*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(8) 2541*cfb92d14SAndroid Build Coastguard Worker timeout = 1 2542*cfb92d14SAndroid Build Coastguard Worker else: 2543*cfb92d14SAndroid Build Coastguard Worker timeout = 8 2544*cfb92d14SAndroid Build Coastguard Worker 2545*cfb92d14SAndroid Build Coastguard Worker self._expect_done(timeout=timeout) 2546*cfb92d14SAndroid Build Coastguard Worker 2547*cfb92d14SAndroid Build Coastguard Worker def send_network_diag_reset(self, addr, tlv_types): 2548*cfb92d14SAndroid Build Coastguard Worker self.send_command('networkdiagnostic reset %s %s' % (addr, ' '.join([str(t.value) for t in tlv_types]))) 2549*cfb92d14SAndroid Build Coastguard Worker 2550*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 2551*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(8) 2552*cfb92d14SAndroid Build Coastguard Worker timeout = 1 2553*cfb92d14SAndroid Build Coastguard Worker else: 2554*cfb92d14SAndroid Build Coastguard Worker timeout = 8 2555*cfb92d14SAndroid Build Coastguard Worker 2556*cfb92d14SAndroid Build Coastguard Worker self._expect_done(timeout=timeout) 2557*cfb92d14SAndroid Build Coastguard Worker 2558*cfb92d14SAndroid Build Coastguard Worker def energy_scan(self, mask, count, period, scan_duration, ipaddr): 2559*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner energy %d %d %d %d %s' % ( 2560*cfb92d14SAndroid Build Coastguard Worker mask, 2561*cfb92d14SAndroid Build Coastguard Worker count, 2562*cfb92d14SAndroid Build Coastguard Worker period, 2563*cfb92d14SAndroid Build Coastguard Worker scan_duration, 2564*cfb92d14SAndroid Build Coastguard Worker ipaddr, 2565*cfb92d14SAndroid Build Coastguard Worker ) 2566*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2567*cfb92d14SAndroid Build Coastguard Worker 2568*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 2569*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(8) 2570*cfb92d14SAndroid Build Coastguard Worker timeout = 1 2571*cfb92d14SAndroid Build Coastguard Worker else: 2572*cfb92d14SAndroid Build Coastguard Worker timeout = 8 2573*cfb92d14SAndroid Build Coastguard Worker 2574*cfb92d14SAndroid Build Coastguard Worker self._expect('Energy:', timeout=timeout) 2575*cfb92d14SAndroid Build Coastguard Worker 2576*cfb92d14SAndroid Build Coastguard Worker def panid_query(self, panid, mask, ipaddr): 2577*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner panid %d %d %s' % (panid, mask, ipaddr) 2578*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2579*cfb92d14SAndroid Build Coastguard Worker 2580*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 2581*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(8) 2582*cfb92d14SAndroid Build Coastguard Worker timeout = 1 2583*cfb92d14SAndroid Build Coastguard Worker else: 2584*cfb92d14SAndroid Build Coastguard Worker timeout = 8 2585*cfb92d14SAndroid Build Coastguard Worker 2586*cfb92d14SAndroid Build Coastguard Worker self._expect('Conflict:', timeout=timeout) 2587*cfb92d14SAndroid Build Coastguard Worker 2588*cfb92d14SAndroid Build Coastguard Worker def scan(self, result=1, timeout=10): 2589*cfb92d14SAndroid Build Coastguard Worker self.send_command('scan') 2590*cfb92d14SAndroid Build Coastguard Worker 2591*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(timeout) 2592*cfb92d14SAndroid Build Coastguard Worker 2593*cfb92d14SAndroid Build Coastguard Worker if result == 1: 2594*cfb92d14SAndroid Build Coastguard Worker networks = [] 2595*cfb92d14SAndroid Build Coastguard Worker for line in self._expect_command_output()[2:]: 2596*cfb92d14SAndroid Build Coastguard Worker _, panid, extaddr, channel, dbm, lqi, _ = map(str.strip, line.split('|')) 2597*cfb92d14SAndroid Build Coastguard Worker panid = int(panid, 16) 2598*cfb92d14SAndroid Build Coastguard Worker channel, dbm, lqi = map(int, (channel, dbm, lqi)) 2599*cfb92d14SAndroid Build Coastguard Worker 2600*cfb92d14SAndroid Build Coastguard Worker networks.append({ 2601*cfb92d14SAndroid Build Coastguard Worker 'panid': panid, 2602*cfb92d14SAndroid Build Coastguard Worker 'extaddr': extaddr, 2603*cfb92d14SAndroid Build Coastguard Worker 'channel': channel, 2604*cfb92d14SAndroid Build Coastguard Worker 'dbm': dbm, 2605*cfb92d14SAndroid Build Coastguard Worker 'lqi': lqi, 2606*cfb92d14SAndroid Build Coastguard Worker }) 2607*cfb92d14SAndroid Build Coastguard Worker return networks 2608*cfb92d14SAndroid Build Coastguard Worker 2609*cfb92d14SAndroid Build Coastguard Worker def scan_energy(self, timeout=10): 2610*cfb92d14SAndroid Build Coastguard Worker self.send_command('scan energy') 2611*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(timeout) 2612*cfb92d14SAndroid Build Coastguard Worker rssi_list = [] 2613*cfb92d14SAndroid Build Coastguard Worker for line in self._expect_command_output()[2:]: 2614*cfb92d14SAndroid Build Coastguard Worker _, channel, rssi, _ = line.split('|') 2615*cfb92d14SAndroid Build Coastguard Worker rssi_list.append({ 2616*cfb92d14SAndroid Build Coastguard Worker 'channel': int(channel.strip()), 2617*cfb92d14SAndroid Build Coastguard Worker 'rssi': int(rssi.strip()), 2618*cfb92d14SAndroid Build Coastguard Worker }) 2619*cfb92d14SAndroid Build Coastguard Worker return rssi_list 2620*cfb92d14SAndroid Build Coastguard Worker 2621*cfb92d14SAndroid Build Coastguard Worker def ping(self, ipaddr, num_responses=1, size=8, timeout=5, count=1, interval=1, hoplimit=64, interface=None): 2622*cfb92d14SAndroid Build Coastguard Worker args = f'{ipaddr} {size} {count} {interval} {hoplimit} {timeout}' 2623*cfb92d14SAndroid Build Coastguard Worker if interface is not None: 2624*cfb92d14SAndroid Build Coastguard Worker args = f'-I {interface} {args}' 2625*cfb92d14SAndroid Build Coastguard Worker cmd = f'ping {args}' 2626*cfb92d14SAndroid Build Coastguard Worker 2627*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2628*cfb92d14SAndroid Build Coastguard Worker 2629*cfb92d14SAndroid Build Coastguard Worker wait_allowance = 3 2630*cfb92d14SAndroid Build Coastguard Worker end = self.simulator.now() + timeout + wait_allowance 2631*cfb92d14SAndroid Build Coastguard Worker 2632*cfb92d14SAndroid Build Coastguard Worker responders = {} 2633*cfb92d14SAndroid Build Coastguard Worker 2634*cfb92d14SAndroid Build Coastguard Worker result = True 2635*cfb92d14SAndroid Build Coastguard Worker # ncp-sim doesn't print Done 2636*cfb92d14SAndroid Build Coastguard Worker done = (self.node_type == 'ncp-sim') 2637*cfb92d14SAndroid Build Coastguard Worker while len(responders) < num_responses or not done: 2638*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(1) 2639*cfb92d14SAndroid Build Coastguard Worker try: 2640*cfb92d14SAndroid Build Coastguard Worker i = self._expect([r'from (\S+):', r'Done'], timeout=0.1) 2641*cfb92d14SAndroid Build Coastguard Worker except (pexpect.TIMEOUT, socket.timeout): 2642*cfb92d14SAndroid Build Coastguard Worker if self.simulator.now() < end: 2643*cfb92d14SAndroid Build Coastguard Worker continue 2644*cfb92d14SAndroid Build Coastguard Worker result = False 2645*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 2646*cfb92d14SAndroid Build Coastguard Worker self.simulator.sync_devices() 2647*cfb92d14SAndroid Build Coastguard Worker break 2648*cfb92d14SAndroid Build Coastguard Worker else: 2649*cfb92d14SAndroid Build Coastguard Worker if i == 0: 2650*cfb92d14SAndroid Build Coastguard Worker responders[self.pexpect.match.groups()[0]] = 1 2651*cfb92d14SAndroid Build Coastguard Worker elif i == 1: 2652*cfb92d14SAndroid Build Coastguard Worker done = True 2653*cfb92d14SAndroid Build Coastguard Worker return result 2654*cfb92d14SAndroid Build Coastguard Worker 2655*cfb92d14SAndroid Build Coastguard Worker def reset(self): 2656*cfb92d14SAndroid Build Coastguard Worker self._reset('reset') 2657*cfb92d14SAndroid Build Coastguard Worker 2658*cfb92d14SAndroid Build Coastguard Worker def factory_reset(self): 2659*cfb92d14SAndroid Build Coastguard Worker self._reset('factoryreset') 2660*cfb92d14SAndroid Build Coastguard Worker 2661*cfb92d14SAndroid Build Coastguard Worker def _reset(self, cmd): 2662*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, expect_command_echo=False) 2663*cfb92d14SAndroid Build Coastguard Worker time.sleep(self.RESET_DELAY) 2664*cfb92d14SAndroid Build Coastguard Worker # Send a "version" command and drain the CLI output after reset 2665*cfb92d14SAndroid Build Coastguard Worker self.send_command('version', expect_command_echo=False) 2666*cfb92d14SAndroid Build Coastguard Worker while True: 2667*cfb92d14SAndroid Build Coastguard Worker try: 2668*cfb92d14SAndroid Build Coastguard Worker self._expect(r"[^\n]+\n", timeout=0.1) 2669*cfb92d14SAndroid Build Coastguard Worker continue 2670*cfb92d14SAndroid Build Coastguard Worker except pexpect.TIMEOUT: 2671*cfb92d14SAndroid Build Coastguard Worker break 2672*cfb92d14SAndroid Build Coastguard Worker 2673*cfb92d14SAndroid Build Coastguard Worker if self.is_otbr: 2674*cfb92d14SAndroid Build Coastguard Worker self.set_log_level(5) 2675*cfb92d14SAndroid Build Coastguard Worker 2676*cfb92d14SAndroid Build Coastguard Worker def set_router_selection_jitter(self, jitter): 2677*cfb92d14SAndroid Build Coastguard Worker cmd = 'routerselectionjitter %d' % jitter 2678*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2679*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2680*cfb92d14SAndroid Build Coastguard Worker 2681*cfb92d14SAndroid Build Coastguard Worker def set_active_dataset( 2682*cfb92d14SAndroid Build Coastguard Worker self, 2683*cfb92d14SAndroid Build Coastguard Worker timestamp=None, 2684*cfb92d14SAndroid Build Coastguard Worker channel=None, 2685*cfb92d14SAndroid Build Coastguard Worker channel_mask=None, 2686*cfb92d14SAndroid Build Coastguard Worker extended_panid=None, 2687*cfb92d14SAndroid Build Coastguard Worker mesh_local_prefix=None, 2688*cfb92d14SAndroid Build Coastguard Worker network_key=None, 2689*cfb92d14SAndroid Build Coastguard Worker network_name=None, 2690*cfb92d14SAndroid Build Coastguard Worker panid=None, 2691*cfb92d14SAndroid Build Coastguard Worker pskc=None, 2692*cfb92d14SAndroid Build Coastguard Worker security_policy=[], 2693*cfb92d14SAndroid Build Coastguard Worker updateExisting=False, 2694*cfb92d14SAndroid Build Coastguard Worker ): 2695*cfb92d14SAndroid Build Coastguard Worker 2696*cfb92d14SAndroid Build Coastguard Worker if updateExisting: 2697*cfb92d14SAndroid Build Coastguard Worker self.send_command('dataset init active', go=False) 2698*cfb92d14SAndroid Build Coastguard Worker else: 2699*cfb92d14SAndroid Build Coastguard Worker self.send_command('dataset clear', go=False) 2700*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2701*cfb92d14SAndroid Build Coastguard Worker 2702*cfb92d14SAndroid Build Coastguard Worker if timestamp is not None: 2703*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset activetimestamp %d' % timestamp 2704*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2705*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2706*cfb92d14SAndroid Build Coastguard Worker 2707*cfb92d14SAndroid Build Coastguard Worker if channel is not None: 2708*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset channel %d' % channel 2709*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2710*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2711*cfb92d14SAndroid Build Coastguard Worker 2712*cfb92d14SAndroid Build Coastguard Worker if channel_mask is not None: 2713*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset channelmask %d' % channel_mask 2714*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2715*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2716*cfb92d14SAndroid Build Coastguard Worker 2717*cfb92d14SAndroid Build Coastguard Worker if extended_panid is not None: 2718*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset extpanid %s' % extended_panid 2719*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2720*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2721*cfb92d14SAndroid Build Coastguard Worker 2722*cfb92d14SAndroid Build Coastguard Worker if mesh_local_prefix is not None: 2723*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset meshlocalprefix %s' % mesh_local_prefix 2724*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2725*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2726*cfb92d14SAndroid Build Coastguard Worker 2727*cfb92d14SAndroid Build Coastguard Worker if network_key is not None: 2728*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset networkkey %s' % network_key 2729*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2730*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2731*cfb92d14SAndroid Build Coastguard Worker 2732*cfb92d14SAndroid Build Coastguard Worker if network_name is not None: 2733*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset networkname %s' % network_name 2734*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2735*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2736*cfb92d14SAndroid Build Coastguard Worker 2737*cfb92d14SAndroid Build Coastguard Worker if panid is not None: 2738*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset panid %d' % panid 2739*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2740*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2741*cfb92d14SAndroid Build Coastguard Worker 2742*cfb92d14SAndroid Build Coastguard Worker if pskc is not None: 2743*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset pskc %s' % pskc 2744*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2745*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2746*cfb92d14SAndroid Build Coastguard Worker 2747*cfb92d14SAndroid Build Coastguard Worker if security_policy is not None: 2748*cfb92d14SAndroid Build Coastguard Worker if len(security_policy) >= 2: 2749*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset securitypolicy %s %s' % ( 2750*cfb92d14SAndroid Build Coastguard Worker str(security_policy[0]), 2751*cfb92d14SAndroid Build Coastguard Worker security_policy[1], 2752*cfb92d14SAndroid Build Coastguard Worker ) 2753*cfb92d14SAndroid Build Coastguard Worker if len(security_policy) >= 3: 2754*cfb92d14SAndroid Build Coastguard Worker cmd += ' %s' % (str(security_policy[2])) 2755*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd, go=False) 2756*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2757*cfb92d14SAndroid Build Coastguard Worker 2758*cfb92d14SAndroid Build Coastguard Worker self.send_command('dataset commit active', go=False) 2759*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2760*cfb92d14SAndroid Build Coastguard Worker 2761*cfb92d14SAndroid Build Coastguard Worker def set_pending_dataset(self, pendingtimestamp, activetimestamp, panid=None, channel=None, delay=None): 2762*cfb92d14SAndroid Build Coastguard Worker self.send_command('dataset clear') 2763*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2764*cfb92d14SAndroid Build Coastguard Worker 2765*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset pendingtimestamp %d' % pendingtimestamp 2766*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2767*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2768*cfb92d14SAndroid Build Coastguard Worker 2769*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset activetimestamp %d' % activetimestamp 2770*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2771*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2772*cfb92d14SAndroid Build Coastguard Worker 2773*cfb92d14SAndroid Build Coastguard Worker if panid is not None: 2774*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset panid %d' % panid 2775*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2776*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2777*cfb92d14SAndroid Build Coastguard Worker 2778*cfb92d14SAndroid Build Coastguard Worker if channel is not None: 2779*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset channel %d' % channel 2780*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2781*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2782*cfb92d14SAndroid Build Coastguard Worker 2783*cfb92d14SAndroid Build Coastguard Worker if delay is not None: 2784*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset delay %d' % delay 2785*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2786*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2787*cfb92d14SAndroid Build Coastguard Worker 2788*cfb92d14SAndroid Build Coastguard Worker # Set the meshlocal prefix in config.py 2789*cfb92d14SAndroid Build Coastguard Worker self.send_command('dataset meshlocalprefix %s' % config.MESH_LOCAL_PREFIX.split('/')[0]) 2790*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2791*cfb92d14SAndroid Build Coastguard Worker 2792*cfb92d14SAndroid Build Coastguard Worker self.send_command('dataset commit pending') 2793*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2794*cfb92d14SAndroid Build Coastguard Worker 2795*cfb92d14SAndroid Build Coastguard Worker def start_dataset_updater(self, panid=None, channel=None, security_policy=None, delay=None): 2796*cfb92d14SAndroid Build Coastguard Worker self.send_command('dataset clear') 2797*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2798*cfb92d14SAndroid Build Coastguard Worker 2799*cfb92d14SAndroid Build Coastguard Worker if panid is not None: 2800*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset panid %d' % panid 2801*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2802*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2803*cfb92d14SAndroid Build Coastguard Worker 2804*cfb92d14SAndroid Build Coastguard Worker if channel is not None: 2805*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset channel %d' % channel 2806*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2807*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2808*cfb92d14SAndroid Build Coastguard Worker 2809*cfb92d14SAndroid Build Coastguard Worker if security_policy is not None: 2810*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset securitypolicy %d %s ' % (security_policy[0], security_policy[1]) 2811*cfb92d14SAndroid Build Coastguard Worker if (len(security_policy) >= 3): 2812*cfb92d14SAndroid Build Coastguard Worker cmd += '%d ' % (security_policy[2]) 2813*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2814*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2815*cfb92d14SAndroid Build Coastguard Worker 2816*cfb92d14SAndroid Build Coastguard Worker if delay is not None: 2817*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset delay %d ' % delay 2818*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2819*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2820*cfb92d14SAndroid Build Coastguard Worker 2821*cfb92d14SAndroid Build Coastguard Worker self.send_command('dataset updater start') 2822*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2823*cfb92d14SAndroid Build Coastguard Worker 2824*cfb92d14SAndroid Build Coastguard Worker def announce_begin(self, mask, count, period, ipaddr): 2825*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner announce %d %d %d %s' % ( 2826*cfb92d14SAndroid Build Coastguard Worker mask, 2827*cfb92d14SAndroid Build Coastguard Worker count, 2828*cfb92d14SAndroid Build Coastguard Worker period, 2829*cfb92d14SAndroid Build Coastguard Worker ipaddr, 2830*cfb92d14SAndroid Build Coastguard Worker ) 2831*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2832*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2833*cfb92d14SAndroid Build Coastguard Worker 2834*cfb92d14SAndroid Build Coastguard Worker def send_mgmt_active_set( 2835*cfb92d14SAndroid Build Coastguard Worker self, 2836*cfb92d14SAndroid Build Coastguard Worker active_timestamp=None, 2837*cfb92d14SAndroid Build Coastguard Worker channel=None, 2838*cfb92d14SAndroid Build Coastguard Worker channel_mask=None, 2839*cfb92d14SAndroid Build Coastguard Worker extended_panid=None, 2840*cfb92d14SAndroid Build Coastguard Worker panid=None, 2841*cfb92d14SAndroid Build Coastguard Worker network_key=None, 2842*cfb92d14SAndroid Build Coastguard Worker mesh_local=None, 2843*cfb92d14SAndroid Build Coastguard Worker network_name=None, 2844*cfb92d14SAndroid Build Coastguard Worker security_policy=None, 2845*cfb92d14SAndroid Build Coastguard Worker binary=None, 2846*cfb92d14SAndroid Build Coastguard Worker ): 2847*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset mgmtsetcommand active ' 2848*cfb92d14SAndroid Build Coastguard Worker 2849*cfb92d14SAndroid Build Coastguard Worker if active_timestamp is not None: 2850*cfb92d14SAndroid Build Coastguard Worker cmd += 'activetimestamp %d ' % active_timestamp 2851*cfb92d14SAndroid Build Coastguard Worker 2852*cfb92d14SAndroid Build Coastguard Worker if channel is not None: 2853*cfb92d14SAndroid Build Coastguard Worker cmd += 'channel %d ' % channel 2854*cfb92d14SAndroid Build Coastguard Worker 2855*cfb92d14SAndroid Build Coastguard Worker if channel_mask is not None: 2856*cfb92d14SAndroid Build Coastguard Worker cmd += 'channelmask %d ' % channel_mask 2857*cfb92d14SAndroid Build Coastguard Worker 2858*cfb92d14SAndroid Build Coastguard Worker if extended_panid is not None: 2859*cfb92d14SAndroid Build Coastguard Worker cmd += 'extpanid %s ' % extended_panid 2860*cfb92d14SAndroid Build Coastguard Worker 2861*cfb92d14SAndroid Build Coastguard Worker if panid is not None: 2862*cfb92d14SAndroid Build Coastguard Worker cmd += 'panid %d ' % panid 2863*cfb92d14SAndroid Build Coastguard Worker 2864*cfb92d14SAndroid Build Coastguard Worker if network_key is not None: 2865*cfb92d14SAndroid Build Coastguard Worker cmd += 'networkkey %s ' % network_key 2866*cfb92d14SAndroid Build Coastguard Worker 2867*cfb92d14SAndroid Build Coastguard Worker if mesh_local is not None: 2868*cfb92d14SAndroid Build Coastguard Worker cmd += 'localprefix %s ' % mesh_local 2869*cfb92d14SAndroid Build Coastguard Worker 2870*cfb92d14SAndroid Build Coastguard Worker if network_name is not None: 2871*cfb92d14SAndroid Build Coastguard Worker cmd += 'networkname %s ' % self._escape_escapable(network_name) 2872*cfb92d14SAndroid Build Coastguard Worker 2873*cfb92d14SAndroid Build Coastguard Worker if security_policy is not None: 2874*cfb92d14SAndroid Build Coastguard Worker cmd += 'securitypolicy %d %s ' % (security_policy[0], security_policy[1]) 2875*cfb92d14SAndroid Build Coastguard Worker if (len(security_policy) >= 3): 2876*cfb92d14SAndroid Build Coastguard Worker cmd += '%d ' % (security_policy[2]) 2877*cfb92d14SAndroid Build Coastguard Worker 2878*cfb92d14SAndroid Build Coastguard Worker if binary is not None: 2879*cfb92d14SAndroid Build Coastguard Worker cmd += '-x %s ' % binary 2880*cfb92d14SAndroid Build Coastguard Worker 2881*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2882*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2883*cfb92d14SAndroid Build Coastguard Worker 2884*cfb92d14SAndroid Build Coastguard Worker def send_mgmt_active_get(self, addr='', tlvs=[]): 2885*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset mgmtgetcommand active' 2886*cfb92d14SAndroid Build Coastguard Worker 2887*cfb92d14SAndroid Build Coastguard Worker if addr != '': 2888*cfb92d14SAndroid Build Coastguard Worker cmd += ' address ' 2889*cfb92d14SAndroid Build Coastguard Worker cmd += addr 2890*cfb92d14SAndroid Build Coastguard Worker 2891*cfb92d14SAndroid Build Coastguard Worker if len(tlvs) != 0: 2892*cfb92d14SAndroid Build Coastguard Worker tlv_str = ''.join('%02x' % tlv for tlv in tlvs) 2893*cfb92d14SAndroid Build Coastguard Worker cmd += ' -x ' 2894*cfb92d14SAndroid Build Coastguard Worker cmd += tlv_str 2895*cfb92d14SAndroid Build Coastguard Worker 2896*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2897*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2898*cfb92d14SAndroid Build Coastguard Worker 2899*cfb92d14SAndroid Build Coastguard Worker def send_mgmt_pending_get(self, addr='', tlvs=[]): 2900*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset mgmtgetcommand pending' 2901*cfb92d14SAndroid Build Coastguard Worker 2902*cfb92d14SAndroid Build Coastguard Worker if addr != '': 2903*cfb92d14SAndroid Build Coastguard Worker cmd += ' address ' 2904*cfb92d14SAndroid Build Coastguard Worker cmd += addr 2905*cfb92d14SAndroid Build Coastguard Worker 2906*cfb92d14SAndroid Build Coastguard Worker if len(tlvs) != 0: 2907*cfb92d14SAndroid Build Coastguard Worker tlv_str = ''.join('%02x' % tlv for tlv in tlvs) 2908*cfb92d14SAndroid Build Coastguard Worker cmd += ' -x ' 2909*cfb92d14SAndroid Build Coastguard Worker cmd += tlv_str 2910*cfb92d14SAndroid Build Coastguard Worker 2911*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2912*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2913*cfb92d14SAndroid Build Coastguard Worker 2914*cfb92d14SAndroid Build Coastguard Worker def send_mgmt_pending_set( 2915*cfb92d14SAndroid Build Coastguard Worker self, 2916*cfb92d14SAndroid Build Coastguard Worker pending_timestamp=None, 2917*cfb92d14SAndroid Build Coastguard Worker active_timestamp=None, 2918*cfb92d14SAndroid Build Coastguard Worker delay_timer=None, 2919*cfb92d14SAndroid Build Coastguard Worker channel=None, 2920*cfb92d14SAndroid Build Coastguard Worker panid=None, 2921*cfb92d14SAndroid Build Coastguard Worker network_key=None, 2922*cfb92d14SAndroid Build Coastguard Worker mesh_local=None, 2923*cfb92d14SAndroid Build Coastguard Worker network_name=None, 2924*cfb92d14SAndroid Build Coastguard Worker ): 2925*cfb92d14SAndroid Build Coastguard Worker cmd = 'dataset mgmtsetcommand pending ' 2926*cfb92d14SAndroid Build Coastguard Worker if pending_timestamp is not None: 2927*cfb92d14SAndroid Build Coastguard Worker cmd += 'pendingtimestamp %d ' % pending_timestamp 2928*cfb92d14SAndroid Build Coastguard Worker 2929*cfb92d14SAndroid Build Coastguard Worker if active_timestamp is not None: 2930*cfb92d14SAndroid Build Coastguard Worker cmd += 'activetimestamp %d ' % active_timestamp 2931*cfb92d14SAndroid Build Coastguard Worker 2932*cfb92d14SAndroid Build Coastguard Worker if delay_timer is not None: 2933*cfb92d14SAndroid Build Coastguard Worker cmd += 'delaytimer %d ' % delay_timer 2934*cfb92d14SAndroid Build Coastguard Worker 2935*cfb92d14SAndroid Build Coastguard Worker if channel is not None: 2936*cfb92d14SAndroid Build Coastguard Worker cmd += 'channel %d ' % channel 2937*cfb92d14SAndroid Build Coastguard Worker 2938*cfb92d14SAndroid Build Coastguard Worker if panid is not None: 2939*cfb92d14SAndroid Build Coastguard Worker cmd += 'panid %d ' % panid 2940*cfb92d14SAndroid Build Coastguard Worker 2941*cfb92d14SAndroid Build Coastguard Worker if network_key is not None: 2942*cfb92d14SAndroid Build Coastguard Worker cmd += 'networkkey %s ' % network_key 2943*cfb92d14SAndroid Build Coastguard Worker 2944*cfb92d14SAndroid Build Coastguard Worker if mesh_local is not None: 2945*cfb92d14SAndroid Build Coastguard Worker cmd += 'localprefix %s ' % mesh_local 2946*cfb92d14SAndroid Build Coastguard Worker 2947*cfb92d14SAndroid Build Coastguard Worker if network_name is not None: 2948*cfb92d14SAndroid Build Coastguard Worker cmd += 'networkname %s ' % self._escape_escapable(network_name) 2949*cfb92d14SAndroid Build Coastguard Worker 2950*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2951*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2952*cfb92d14SAndroid Build Coastguard Worker 2953*cfb92d14SAndroid Build Coastguard Worker def coap_cancel(self): 2954*cfb92d14SAndroid Build Coastguard Worker """ 2955*cfb92d14SAndroid Build Coastguard Worker Cancel a CoAP subscription. 2956*cfb92d14SAndroid Build Coastguard Worker """ 2957*cfb92d14SAndroid Build Coastguard Worker cmd = 'coap cancel' 2958*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 2959*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 2960*cfb92d14SAndroid Build Coastguard Worker 2961*cfb92d14SAndroid Build Coastguard Worker def coap_delete(self, ipaddr, uri, con=False, payload=None): 2962*cfb92d14SAndroid Build Coastguard Worker """ 2963*cfb92d14SAndroid Build Coastguard Worker Send a DELETE request via CoAP. 2964*cfb92d14SAndroid Build Coastguard Worker """ 2965*cfb92d14SAndroid Build Coastguard Worker return self._coap_rq('delete', ipaddr, uri, con, payload) 2966*cfb92d14SAndroid Build Coastguard Worker 2967*cfb92d14SAndroid Build Coastguard Worker def coap_get(self, ipaddr, uri, con=False, payload=None): 2968*cfb92d14SAndroid Build Coastguard Worker """ 2969*cfb92d14SAndroid Build Coastguard Worker Send a GET request via CoAP. 2970*cfb92d14SAndroid Build Coastguard Worker """ 2971*cfb92d14SAndroid Build Coastguard Worker return self._coap_rq('get', ipaddr, uri, con, payload) 2972*cfb92d14SAndroid Build Coastguard Worker 2973*cfb92d14SAndroid Build Coastguard Worker def coap_get_block(self, ipaddr, uri, size=16, count=0): 2974*cfb92d14SAndroid Build Coastguard Worker """ 2975*cfb92d14SAndroid Build Coastguard Worker Send a GET request via CoAP. 2976*cfb92d14SAndroid Build Coastguard Worker """ 2977*cfb92d14SAndroid Build Coastguard Worker return self._coap_rq_block('get', ipaddr, uri, size, count) 2978*cfb92d14SAndroid Build Coastguard Worker 2979*cfb92d14SAndroid Build Coastguard Worker def coap_observe(self, ipaddr, uri, con=False, payload=None): 2980*cfb92d14SAndroid Build Coastguard Worker """ 2981*cfb92d14SAndroid Build Coastguard Worker Send a GET request via CoAP with Observe set. 2982*cfb92d14SAndroid Build Coastguard Worker """ 2983*cfb92d14SAndroid Build Coastguard Worker return self._coap_rq('observe', ipaddr, uri, con, payload) 2984*cfb92d14SAndroid Build Coastguard Worker 2985*cfb92d14SAndroid Build Coastguard Worker def coap_post(self, ipaddr, uri, con=False, payload=None): 2986*cfb92d14SAndroid Build Coastguard Worker """ 2987*cfb92d14SAndroid Build Coastguard Worker Send a POST request via CoAP. 2988*cfb92d14SAndroid Build Coastguard Worker """ 2989*cfb92d14SAndroid Build Coastguard Worker return self._coap_rq('post', ipaddr, uri, con, payload) 2990*cfb92d14SAndroid Build Coastguard Worker 2991*cfb92d14SAndroid Build Coastguard Worker def coap_post_block(self, ipaddr, uri, size=16, count=0): 2992*cfb92d14SAndroid Build Coastguard Worker """ 2993*cfb92d14SAndroid Build Coastguard Worker Send a POST request via CoAP. 2994*cfb92d14SAndroid Build Coastguard Worker """ 2995*cfb92d14SAndroid Build Coastguard Worker return self._coap_rq_block('post', ipaddr, uri, size, count) 2996*cfb92d14SAndroid Build Coastguard Worker 2997*cfb92d14SAndroid Build Coastguard Worker def coap_put(self, ipaddr, uri, con=False, payload=None): 2998*cfb92d14SAndroid Build Coastguard Worker """ 2999*cfb92d14SAndroid Build Coastguard Worker Send a PUT request via CoAP. 3000*cfb92d14SAndroid Build Coastguard Worker """ 3001*cfb92d14SAndroid Build Coastguard Worker return self._coap_rq('put', ipaddr, uri, con, payload) 3002*cfb92d14SAndroid Build Coastguard Worker 3003*cfb92d14SAndroid Build Coastguard Worker def coap_put_block(self, ipaddr, uri, size=16, count=0): 3004*cfb92d14SAndroid Build Coastguard Worker """ 3005*cfb92d14SAndroid Build Coastguard Worker Send a PUT request via CoAP. 3006*cfb92d14SAndroid Build Coastguard Worker """ 3007*cfb92d14SAndroid Build Coastguard Worker return self._coap_rq_block('put', ipaddr, uri, size, count) 3008*cfb92d14SAndroid Build Coastguard Worker 3009*cfb92d14SAndroid Build Coastguard Worker def _coap_rq(self, method, ipaddr, uri, con=False, payload=None): 3010*cfb92d14SAndroid Build Coastguard Worker """ 3011*cfb92d14SAndroid Build Coastguard Worker Issue a GET/POST/PUT/DELETE/GET OBSERVE request. 3012*cfb92d14SAndroid Build Coastguard Worker """ 3013*cfb92d14SAndroid Build Coastguard Worker cmd = 'coap %s %s %s' % (method, ipaddr, uri) 3014*cfb92d14SAndroid Build Coastguard Worker if con: 3015*cfb92d14SAndroid Build Coastguard Worker cmd += ' con' 3016*cfb92d14SAndroid Build Coastguard Worker else: 3017*cfb92d14SAndroid Build Coastguard Worker cmd += ' non' 3018*cfb92d14SAndroid Build Coastguard Worker 3019*cfb92d14SAndroid Build Coastguard Worker if payload is not None: 3020*cfb92d14SAndroid Build Coastguard Worker cmd += ' %s' % payload 3021*cfb92d14SAndroid Build Coastguard Worker 3022*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3023*cfb92d14SAndroid Build Coastguard Worker return self.coap_wait_response() 3024*cfb92d14SAndroid Build Coastguard Worker 3025*cfb92d14SAndroid Build Coastguard Worker def _coap_rq_block(self, method, ipaddr, uri, size=16, count=0): 3026*cfb92d14SAndroid Build Coastguard Worker """ 3027*cfb92d14SAndroid Build Coastguard Worker Issue a GET/POST/PUT/DELETE/GET OBSERVE BLOCK request. 3028*cfb92d14SAndroid Build Coastguard Worker """ 3029*cfb92d14SAndroid Build Coastguard Worker cmd = 'coap %s %s %s' % (method, ipaddr, uri) 3030*cfb92d14SAndroid Build Coastguard Worker 3031*cfb92d14SAndroid Build Coastguard Worker cmd += ' block-%d' % size 3032*cfb92d14SAndroid Build Coastguard Worker 3033*cfb92d14SAndroid Build Coastguard Worker if count != 0: 3034*cfb92d14SAndroid Build Coastguard Worker cmd += ' %d' % count 3035*cfb92d14SAndroid Build Coastguard Worker 3036*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3037*cfb92d14SAndroid Build Coastguard Worker return self.coap_wait_response() 3038*cfb92d14SAndroid Build Coastguard Worker 3039*cfb92d14SAndroid Build Coastguard Worker def coap_wait_response(self): 3040*cfb92d14SAndroid Build Coastguard Worker """ 3041*cfb92d14SAndroid Build Coastguard Worker Wait for a CoAP response, and return it. 3042*cfb92d14SAndroid Build Coastguard Worker """ 3043*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 3044*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3045*cfb92d14SAndroid Build Coastguard Worker timeout = 1 3046*cfb92d14SAndroid Build Coastguard Worker else: 3047*cfb92d14SAndroid Build Coastguard Worker timeout = 5 3048*cfb92d14SAndroid Build Coastguard Worker 3049*cfb92d14SAndroid Build Coastguard Worker self._expect(r'coap response from ([\da-f:]+)(?: OBS=(\d+))?' 3050*cfb92d14SAndroid Build Coastguard Worker r'(?: with payload: ([\da-f]+))?\b', 3051*cfb92d14SAndroid Build Coastguard Worker timeout=timeout) 3052*cfb92d14SAndroid Build Coastguard Worker (source, observe, payload) = self.pexpect.match.groups() 3053*cfb92d14SAndroid Build Coastguard Worker source = source.decode('UTF-8') 3054*cfb92d14SAndroid Build Coastguard Worker 3055*cfb92d14SAndroid Build Coastguard Worker if observe is not None: 3056*cfb92d14SAndroid Build Coastguard Worker observe = int(observe, base=10) 3057*cfb92d14SAndroid Build Coastguard Worker 3058*cfb92d14SAndroid Build Coastguard Worker if payload is not None: 3059*cfb92d14SAndroid Build Coastguard Worker try: 3060*cfb92d14SAndroid Build Coastguard Worker payload = binascii.a2b_hex(payload).decode('UTF-8') 3061*cfb92d14SAndroid Build Coastguard Worker except UnicodeDecodeError: 3062*cfb92d14SAndroid Build Coastguard Worker pass 3063*cfb92d14SAndroid Build Coastguard Worker 3064*cfb92d14SAndroid Build Coastguard Worker # Return the values received 3065*cfb92d14SAndroid Build Coastguard Worker return dict(source=source, observe=observe, payload=payload) 3066*cfb92d14SAndroid Build Coastguard Worker 3067*cfb92d14SAndroid Build Coastguard Worker def coap_wait_request(self): 3068*cfb92d14SAndroid Build Coastguard Worker """ 3069*cfb92d14SAndroid Build Coastguard Worker Wait for a CoAP request to be made. 3070*cfb92d14SAndroid Build Coastguard Worker """ 3071*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 3072*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3073*cfb92d14SAndroid Build Coastguard Worker timeout = 1 3074*cfb92d14SAndroid Build Coastguard Worker else: 3075*cfb92d14SAndroid Build Coastguard Worker timeout = 5 3076*cfb92d14SAndroid Build Coastguard Worker 3077*cfb92d14SAndroid Build Coastguard Worker self._expect(r'coap request from ([\da-f:]+)(?: OBS=(\d+))?' 3078*cfb92d14SAndroid Build Coastguard Worker r'(?: with payload: ([\da-f]+))?\b', 3079*cfb92d14SAndroid Build Coastguard Worker timeout=timeout) 3080*cfb92d14SAndroid Build Coastguard Worker (source, observe, payload) = self.pexpect.match.groups() 3081*cfb92d14SAndroid Build Coastguard Worker source = source.decode('UTF-8') 3082*cfb92d14SAndroid Build Coastguard Worker 3083*cfb92d14SAndroid Build Coastguard Worker if observe is not None: 3084*cfb92d14SAndroid Build Coastguard Worker observe = int(observe, base=10) 3085*cfb92d14SAndroid Build Coastguard Worker 3086*cfb92d14SAndroid Build Coastguard Worker if payload is not None: 3087*cfb92d14SAndroid Build Coastguard Worker payload = binascii.a2b_hex(payload).decode('UTF-8') 3088*cfb92d14SAndroid Build Coastguard Worker 3089*cfb92d14SAndroid Build Coastguard Worker # Return the values received 3090*cfb92d14SAndroid Build Coastguard Worker return dict(source=source, observe=observe, payload=payload) 3091*cfb92d14SAndroid Build Coastguard Worker 3092*cfb92d14SAndroid Build Coastguard Worker def coap_wait_subscribe(self): 3093*cfb92d14SAndroid Build Coastguard Worker """ 3094*cfb92d14SAndroid Build Coastguard Worker Wait for a CoAP client to be subscribed. 3095*cfb92d14SAndroid Build Coastguard Worker """ 3096*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 3097*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3098*cfb92d14SAndroid Build Coastguard Worker timeout = 1 3099*cfb92d14SAndroid Build Coastguard Worker else: 3100*cfb92d14SAndroid Build Coastguard Worker timeout = 5 3101*cfb92d14SAndroid Build Coastguard Worker 3102*cfb92d14SAndroid Build Coastguard Worker self._expect(r'Subscribing client\b', timeout=timeout) 3103*cfb92d14SAndroid Build Coastguard Worker 3104*cfb92d14SAndroid Build Coastguard Worker def coap_wait_ack(self): 3105*cfb92d14SAndroid Build Coastguard Worker """ 3106*cfb92d14SAndroid Build Coastguard Worker Wait for a CoAP notification ACK. 3107*cfb92d14SAndroid Build Coastguard Worker """ 3108*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 3109*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3110*cfb92d14SAndroid Build Coastguard Worker timeout = 1 3111*cfb92d14SAndroid Build Coastguard Worker else: 3112*cfb92d14SAndroid Build Coastguard Worker timeout = 5 3113*cfb92d14SAndroid Build Coastguard Worker 3114*cfb92d14SAndroid Build Coastguard Worker self._expect(r'Received ACK in reply to notification from ([\da-f:]+)\b', timeout=timeout) 3115*cfb92d14SAndroid Build Coastguard Worker (source,) = self.pexpect.match.groups() 3116*cfb92d14SAndroid Build Coastguard Worker source = source.decode('UTF-8') 3117*cfb92d14SAndroid Build Coastguard Worker 3118*cfb92d14SAndroid Build Coastguard Worker return source 3119*cfb92d14SAndroid Build Coastguard Worker 3120*cfb92d14SAndroid Build Coastguard Worker def coap_set_resource_path(self, path): 3121*cfb92d14SAndroid Build Coastguard Worker """ 3122*cfb92d14SAndroid Build Coastguard Worker Set the path for the CoAP resource. 3123*cfb92d14SAndroid Build Coastguard Worker """ 3124*cfb92d14SAndroid Build Coastguard Worker cmd = 'coap resource %s' % path 3125*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3126*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3127*cfb92d14SAndroid Build Coastguard Worker 3128*cfb92d14SAndroid Build Coastguard Worker def coap_set_resource_path_block(self, path, count=0): 3129*cfb92d14SAndroid Build Coastguard Worker """ 3130*cfb92d14SAndroid Build Coastguard Worker Set the path for the CoAP resource and how many blocks can be received from this resource. 3131*cfb92d14SAndroid Build Coastguard Worker """ 3132*cfb92d14SAndroid Build Coastguard Worker cmd = 'coap resource %s %d' % (path, count) 3133*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3134*cfb92d14SAndroid Build Coastguard Worker self._expect('Done') 3135*cfb92d14SAndroid Build Coastguard Worker 3136*cfb92d14SAndroid Build Coastguard Worker def coap_set_content(self, content): 3137*cfb92d14SAndroid Build Coastguard Worker """ 3138*cfb92d14SAndroid Build Coastguard Worker Set the content of the CoAP resource. 3139*cfb92d14SAndroid Build Coastguard Worker """ 3140*cfb92d14SAndroid Build Coastguard Worker cmd = 'coap set %s' % content 3141*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3142*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3143*cfb92d14SAndroid Build Coastguard Worker 3144*cfb92d14SAndroid Build Coastguard Worker def coap_start(self): 3145*cfb92d14SAndroid Build Coastguard Worker """ 3146*cfb92d14SAndroid Build Coastguard Worker Start the CoAP service. 3147*cfb92d14SAndroid Build Coastguard Worker """ 3148*cfb92d14SAndroid Build Coastguard Worker cmd = 'coap start' 3149*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3150*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3151*cfb92d14SAndroid Build Coastguard Worker 3152*cfb92d14SAndroid Build Coastguard Worker def coap_stop(self): 3153*cfb92d14SAndroid Build Coastguard Worker """ 3154*cfb92d14SAndroid Build Coastguard Worker Stop the CoAP service. 3155*cfb92d14SAndroid Build Coastguard Worker """ 3156*cfb92d14SAndroid Build Coastguard Worker cmd = 'coap stop' 3157*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3158*cfb92d14SAndroid Build Coastguard Worker 3159*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 3160*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3161*cfb92d14SAndroid Build Coastguard Worker timeout = 1 3162*cfb92d14SAndroid Build Coastguard Worker else: 3163*cfb92d14SAndroid Build Coastguard Worker timeout = 5 3164*cfb92d14SAndroid Build Coastguard Worker 3165*cfb92d14SAndroid Build Coastguard Worker self._expect_done(timeout=timeout) 3166*cfb92d14SAndroid Build Coastguard Worker 3167*cfb92d14SAndroid Build Coastguard Worker def coaps_start_psk(self, psk, pskIdentity): 3168*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps psk %s %s' % (psk, pskIdentity) 3169*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3170*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3171*cfb92d14SAndroid Build Coastguard Worker 3172*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps start' 3173*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3174*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3175*cfb92d14SAndroid Build Coastguard Worker 3176*cfb92d14SAndroid Build Coastguard Worker def coaps_start_x509(self): 3177*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps x509' 3178*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3179*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3180*cfb92d14SAndroid Build Coastguard Worker 3181*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps start' 3182*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3183*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3184*cfb92d14SAndroid Build Coastguard Worker 3185*cfb92d14SAndroid Build Coastguard Worker def coaps_set_resource_path(self, path): 3186*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps resource %s' % path 3187*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3188*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3189*cfb92d14SAndroid Build Coastguard Worker 3190*cfb92d14SAndroid Build Coastguard Worker def coaps_stop(self): 3191*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps stop' 3192*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3193*cfb92d14SAndroid Build Coastguard Worker 3194*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 3195*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3196*cfb92d14SAndroid Build Coastguard Worker timeout = 1 3197*cfb92d14SAndroid Build Coastguard Worker else: 3198*cfb92d14SAndroid Build Coastguard Worker timeout = 5 3199*cfb92d14SAndroid Build Coastguard Worker 3200*cfb92d14SAndroid Build Coastguard Worker self._expect_done(timeout=timeout) 3201*cfb92d14SAndroid Build Coastguard Worker 3202*cfb92d14SAndroid Build Coastguard Worker def coaps_connect(self, ipaddr): 3203*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps connect %s' % ipaddr 3204*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3205*cfb92d14SAndroid Build Coastguard Worker 3206*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 3207*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3208*cfb92d14SAndroid Build Coastguard Worker timeout = 1 3209*cfb92d14SAndroid Build Coastguard Worker else: 3210*cfb92d14SAndroid Build Coastguard Worker timeout = 5 3211*cfb92d14SAndroid Build Coastguard Worker 3212*cfb92d14SAndroid Build Coastguard Worker self._expect('coaps connected', timeout=timeout) 3213*cfb92d14SAndroid Build Coastguard Worker 3214*cfb92d14SAndroid Build Coastguard Worker def coaps_disconnect(self): 3215*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps disconnect' 3216*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3217*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3218*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3219*cfb92d14SAndroid Build Coastguard Worker 3220*cfb92d14SAndroid Build Coastguard Worker def coaps_get(self): 3221*cfb92d14SAndroid Build Coastguard Worker cmd = 'coaps get test' 3222*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3223*cfb92d14SAndroid Build Coastguard Worker 3224*cfb92d14SAndroid Build Coastguard Worker if isinstance(self.simulator, simulator.VirtualTime): 3225*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3226*cfb92d14SAndroid Build Coastguard Worker timeout = 1 3227*cfb92d14SAndroid Build Coastguard Worker else: 3228*cfb92d14SAndroid Build Coastguard Worker timeout = 5 3229*cfb92d14SAndroid Build Coastguard Worker 3230*cfb92d14SAndroid Build Coastguard Worker self._expect('coaps response', timeout=timeout) 3231*cfb92d14SAndroid Build Coastguard Worker 3232*cfb92d14SAndroid Build Coastguard Worker def commissioner_mgmtget(self, tlvs_binary=None): 3233*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner mgmtget' 3234*cfb92d14SAndroid Build Coastguard Worker if tlvs_binary is not None: 3235*cfb92d14SAndroid Build Coastguard Worker cmd += ' -x %s' % tlvs_binary 3236*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3237*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3238*cfb92d14SAndroid Build Coastguard Worker 3239*cfb92d14SAndroid Build Coastguard Worker def commissioner_mgmtset(self, tlvs_binary): 3240*cfb92d14SAndroid Build Coastguard Worker cmd = 'commissioner mgmtset -x %s' % tlvs_binary 3241*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3242*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3243*cfb92d14SAndroid Build Coastguard Worker 3244*cfb92d14SAndroid Build Coastguard Worker def bytes_to_hex_str(self, src): 3245*cfb92d14SAndroid Build Coastguard Worker return ''.join(format(x, '02x') for x in src) 3246*cfb92d14SAndroid Build Coastguard Worker 3247*cfb92d14SAndroid Build Coastguard Worker def commissioner_mgmtset_with_tlvs(self, tlvs): 3248*cfb92d14SAndroid Build Coastguard Worker payload = bytearray() 3249*cfb92d14SAndroid Build Coastguard Worker for tlv in tlvs: 3250*cfb92d14SAndroid Build Coastguard Worker payload += tlv.to_hex() 3251*cfb92d14SAndroid Build Coastguard Worker self.commissioner_mgmtset(self.bytes_to_hex_str(payload)) 3252*cfb92d14SAndroid Build Coastguard Worker 3253*cfb92d14SAndroid Build Coastguard Worker def udp_start(self, local_ipaddr, local_port, bind_unspecified=False): 3254*cfb92d14SAndroid Build Coastguard Worker cmd = 'udp open' 3255*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3256*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3257*cfb92d14SAndroid Build Coastguard Worker 3258*cfb92d14SAndroid Build Coastguard Worker cmd = 'udp bind %s %s %s' % ("-u" if bind_unspecified else "", local_ipaddr, local_port) 3259*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3260*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3261*cfb92d14SAndroid Build Coastguard Worker 3262*cfb92d14SAndroid Build Coastguard Worker def udp_stop(self): 3263*cfb92d14SAndroid Build Coastguard Worker cmd = 'udp close' 3264*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3265*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3266*cfb92d14SAndroid Build Coastguard Worker 3267*cfb92d14SAndroid Build Coastguard Worker def udp_send(self, bytes, ipaddr, port, success=True): 3268*cfb92d14SAndroid Build Coastguard Worker cmd = 'udp send %s %d -s %d ' % (ipaddr, port, bytes) 3269*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3270*cfb92d14SAndroid Build Coastguard Worker if success: 3271*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3272*cfb92d14SAndroid Build Coastguard Worker else: 3273*cfb92d14SAndroid Build Coastguard Worker self._expect('Error') 3274*cfb92d14SAndroid Build Coastguard Worker 3275*cfb92d14SAndroid Build Coastguard Worker def udp_check_rx(self, bytes_should_rx): 3276*cfb92d14SAndroid Build Coastguard Worker self._expect('%d bytes' % bytes_should_rx) 3277*cfb92d14SAndroid Build Coastguard Worker 3278*cfb92d14SAndroid Build Coastguard Worker def set_routereligible(self, enable: bool): 3279*cfb92d14SAndroid Build Coastguard Worker cmd = f'routereligible {"enable" if enable else "disable"}' 3280*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3281*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3282*cfb92d14SAndroid Build Coastguard Worker 3283*cfb92d14SAndroid Build Coastguard Worker def router_list(self): 3284*cfb92d14SAndroid Build Coastguard Worker cmd = 'router list' 3285*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3286*cfb92d14SAndroid Build Coastguard Worker self._expect([r'(\d+)((\s\d+)*)']) 3287*cfb92d14SAndroid Build Coastguard Worker 3288*cfb92d14SAndroid Build Coastguard Worker g = self.pexpect.match.groups() 3289*cfb92d14SAndroid Build Coastguard Worker router_list = g[0].decode('utf8') + ' ' + g[1].decode('utf8') 3290*cfb92d14SAndroid Build Coastguard Worker router_list = [int(x) for x in router_list.split()] 3291*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3292*cfb92d14SAndroid Build Coastguard Worker return router_list 3293*cfb92d14SAndroid Build Coastguard Worker 3294*cfb92d14SAndroid Build Coastguard Worker def router_table(self): 3295*cfb92d14SAndroid Build Coastguard Worker cmd = 'router table' 3296*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3297*cfb92d14SAndroid Build Coastguard Worker 3298*cfb92d14SAndroid Build Coastguard Worker self._expect(r'(.*)Done') 3299*cfb92d14SAndroid Build Coastguard Worker g = self.pexpect.match.groups() 3300*cfb92d14SAndroid Build Coastguard Worker output = g[0].decode('utf8') 3301*cfb92d14SAndroid Build Coastguard Worker lines = output.strip().split('\n') 3302*cfb92d14SAndroid Build Coastguard Worker lines = [l.strip() for l in lines] 3303*cfb92d14SAndroid Build Coastguard Worker router_table = {} 3304*cfb92d14SAndroid Build Coastguard Worker for i, line in enumerate(lines): 3305*cfb92d14SAndroid Build Coastguard Worker if not line.startswith('|') or not line.endswith('|'): 3306*cfb92d14SAndroid Build Coastguard Worker if i not in (0, 2): 3307*cfb92d14SAndroid Build Coastguard Worker # should not happen 3308*cfb92d14SAndroid Build Coastguard Worker print("unexpected line %d: %s" % (i, line)) 3309*cfb92d14SAndroid Build Coastguard Worker 3310*cfb92d14SAndroid Build Coastguard Worker continue 3311*cfb92d14SAndroid Build Coastguard Worker 3312*cfb92d14SAndroid Build Coastguard Worker line = line[1:][:-1] 3313*cfb92d14SAndroid Build Coastguard Worker line = [x.strip() for x in line.split('|')] 3314*cfb92d14SAndroid Build Coastguard Worker if len(line) < 9: 3315*cfb92d14SAndroid Build Coastguard Worker print("unexpected line %d: %s" % (i, line)) 3316*cfb92d14SAndroid Build Coastguard Worker continue 3317*cfb92d14SAndroid Build Coastguard Worker 3318*cfb92d14SAndroid Build Coastguard Worker try: 3319*cfb92d14SAndroid Build Coastguard Worker int(line[0]) 3320*cfb92d14SAndroid Build Coastguard Worker except ValueError: 3321*cfb92d14SAndroid Build Coastguard Worker if i != 1: 3322*cfb92d14SAndroid Build Coastguard Worker print("unexpected line %d: %s" % (i, line)) 3323*cfb92d14SAndroid Build Coastguard Worker continue 3324*cfb92d14SAndroid Build Coastguard Worker 3325*cfb92d14SAndroid Build Coastguard Worker id = int(line[0]) 3326*cfb92d14SAndroid Build Coastguard Worker rloc16 = int(line[1], 16) 3327*cfb92d14SAndroid Build Coastguard Worker nexthop = int(line[2]) 3328*cfb92d14SAndroid Build Coastguard Worker pathcost = int(line[3]) 3329*cfb92d14SAndroid Build Coastguard Worker lqin = int(line[4]) 3330*cfb92d14SAndroid Build Coastguard Worker lqout = int(line[5]) 3331*cfb92d14SAndroid Build Coastguard Worker age = int(line[6]) 3332*cfb92d14SAndroid Build Coastguard Worker emac = str(line[7]) 3333*cfb92d14SAndroid Build Coastguard Worker link = int(line[8]) 3334*cfb92d14SAndroid Build Coastguard Worker 3335*cfb92d14SAndroid Build Coastguard Worker router_table[id] = { 3336*cfb92d14SAndroid Build Coastguard Worker 'rloc16': rloc16, 3337*cfb92d14SAndroid Build Coastguard Worker 'nexthop': nexthop, 3338*cfb92d14SAndroid Build Coastguard Worker 'pathcost': pathcost, 3339*cfb92d14SAndroid Build Coastguard Worker 'lqin': lqin, 3340*cfb92d14SAndroid Build Coastguard Worker 'lqout': lqout, 3341*cfb92d14SAndroid Build Coastguard Worker 'age': age, 3342*cfb92d14SAndroid Build Coastguard Worker 'emac': emac, 3343*cfb92d14SAndroid Build Coastguard Worker 'link': link, 3344*cfb92d14SAndroid Build Coastguard Worker } 3345*cfb92d14SAndroid Build Coastguard Worker 3346*cfb92d14SAndroid Build Coastguard Worker return router_table 3347*cfb92d14SAndroid Build Coastguard Worker 3348*cfb92d14SAndroid Build Coastguard Worker def link_metrics_request_single_probe(self, dst_addr: str, linkmetrics_flags: str, mode: str = ''): 3349*cfb92d14SAndroid Build Coastguard Worker cmd = 'linkmetrics request %s %s single %s' % (mode, dst_addr, linkmetrics_flags) 3350*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3351*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3352*cfb92d14SAndroid Build Coastguard Worker return self._parse_linkmetrics_query_result(self._expect_command_output()) 3353*cfb92d14SAndroid Build Coastguard Worker 3354*cfb92d14SAndroid Build Coastguard Worker def link_metrics_request_forward_tracking_series(self, dst_addr: str, series_id: int, mode: str = ''): 3355*cfb92d14SAndroid Build Coastguard Worker cmd = 'linkmetrics request %s %s forward %d' % (mode, dst_addr, series_id) 3356*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3357*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(5) 3358*cfb92d14SAndroid Build Coastguard Worker return self._parse_linkmetrics_query_result(self._expect_command_output()) 3359*cfb92d14SAndroid Build Coastguard Worker 3360*cfb92d14SAndroid Build Coastguard Worker def _parse_linkmetrics_query_result(self, lines): 3361*cfb92d14SAndroid Build Coastguard Worker """Parse link metrics query result""" 3362*cfb92d14SAndroid Build Coastguard Worker 3363*cfb92d14SAndroid Build Coastguard Worker # Example of command output: 3364*cfb92d14SAndroid Build Coastguard Worker # ['Received Link Metrics Report from: fe80:0:0:0:146e:a00:0:1', 3365*cfb92d14SAndroid Build Coastguard Worker # '- PDU Counter: 1 (Count/Summation)', 3366*cfb92d14SAndroid Build Coastguard Worker # '- LQI: 0 (Exponential Moving Average)', 3367*cfb92d14SAndroid Build Coastguard Worker # '- Margin: 80 (dB) (Exponential Moving Average)', 3368*cfb92d14SAndroid Build Coastguard Worker # '- RSSI: -20 (dBm) (Exponential Moving Average)'] 3369*cfb92d14SAndroid Build Coastguard Worker # 3370*cfb92d14SAndroid Build Coastguard Worker # Or 'Link Metrics Report, status: {status}' 3371*cfb92d14SAndroid Build Coastguard Worker 3372*cfb92d14SAndroid Build Coastguard Worker result = {} 3373*cfb92d14SAndroid Build Coastguard Worker for line in lines: 3374*cfb92d14SAndroid Build Coastguard Worker if line.startswith('- '): 3375*cfb92d14SAndroid Build Coastguard Worker k, v = line[2:].split(': ') 3376*cfb92d14SAndroid Build Coastguard Worker result[k] = v.split(' ')[0] 3377*cfb92d14SAndroid Build Coastguard Worker elif line.startswith('Link Metrics Report, status: '): 3378*cfb92d14SAndroid Build Coastguard Worker result['Status'] = line[29:] 3379*cfb92d14SAndroid Build Coastguard Worker return result 3380*cfb92d14SAndroid Build Coastguard Worker 3381*cfb92d14SAndroid Build Coastguard Worker def link_metrics_config_req_enhanced_ack_based_probing(self, 3382*cfb92d14SAndroid Build Coastguard Worker dst_addr: str, 3383*cfb92d14SAndroid Build Coastguard Worker enable: bool, 3384*cfb92d14SAndroid Build Coastguard Worker metrics_flags: str, 3385*cfb92d14SAndroid Build Coastguard Worker ext_flags='', 3386*cfb92d14SAndroid Build Coastguard Worker mode: str = ''): 3387*cfb92d14SAndroid Build Coastguard Worker cmd = "linkmetrics config %s %s enhanced-ack" % (mode, dst_addr) 3388*cfb92d14SAndroid Build Coastguard Worker if enable: 3389*cfb92d14SAndroid Build Coastguard Worker cmd = cmd + (" register %s %s" % (metrics_flags, ext_flags)) 3390*cfb92d14SAndroid Build Coastguard Worker else: 3391*cfb92d14SAndroid Build Coastguard Worker cmd = cmd + " clear" 3392*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3393*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3394*cfb92d14SAndroid Build Coastguard Worker 3395*cfb92d14SAndroid Build Coastguard Worker def link_metrics_config_req_forward_tracking_series(self, 3396*cfb92d14SAndroid Build Coastguard Worker dst_addr: str, 3397*cfb92d14SAndroid Build Coastguard Worker series_id: int, 3398*cfb92d14SAndroid Build Coastguard Worker series_flags: str, 3399*cfb92d14SAndroid Build Coastguard Worker metrics_flags: str, 3400*cfb92d14SAndroid Build Coastguard Worker mode: str = ''): 3401*cfb92d14SAndroid Build Coastguard Worker cmd = "linkmetrics config %s %s forward %d %s %s" % (mode, dst_addr, series_id, series_flags, metrics_flags) 3402*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3403*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3404*cfb92d14SAndroid Build Coastguard Worker 3405*cfb92d14SAndroid Build Coastguard Worker def link_metrics_send_link_probe(self, dst_addr: str, series_id: int, length: int): 3406*cfb92d14SAndroid Build Coastguard Worker cmd = "linkmetrics probe %s %d %d" % (dst_addr, series_id, length) 3407*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3408*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3409*cfb92d14SAndroid Build Coastguard Worker 3410*cfb92d14SAndroid Build Coastguard Worker def link_metrics_mgr_set_enabled(self, enable: bool): 3411*cfb92d14SAndroid Build Coastguard Worker op_str = "enable" if enable else "disable" 3412*cfb92d14SAndroid Build Coastguard Worker cmd = f'linkmetricsmgr {op_str}' 3413*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3414*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3415*cfb92d14SAndroid Build Coastguard Worker 3416*cfb92d14SAndroid Build Coastguard Worker def send_address_notification(self, dst: str, target: str, mliid: str): 3417*cfb92d14SAndroid Build Coastguard Worker cmd = f'fake /a/an {dst} {target} {mliid}' 3418*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3419*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3420*cfb92d14SAndroid Build Coastguard Worker 3421*cfb92d14SAndroid Build Coastguard Worker def send_proactive_backbone_notification(self, target: str, mliid: str, ltt: int): 3422*cfb92d14SAndroid Build Coastguard Worker cmd = f'fake /b/ba {target} {mliid} {ltt}' 3423*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3424*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3425*cfb92d14SAndroid Build Coastguard Worker 3426*cfb92d14SAndroid Build Coastguard Worker def dns_get_config(self): 3427*cfb92d14SAndroid Build Coastguard Worker """ 3428*cfb92d14SAndroid Build Coastguard Worker Returns the DNS config as a list of property dictionary (string key and string value). 3429*cfb92d14SAndroid Build Coastguard Worker 3430*cfb92d14SAndroid Build Coastguard Worker Example output: 3431*cfb92d14SAndroid Build Coastguard Worker { 3432*cfb92d14SAndroid Build Coastguard Worker 'Server': '[fd00:0:0:0:0:0:0:1]:1234' 3433*cfb92d14SAndroid Build Coastguard Worker 'ResponseTimeout': '5000 ms' 3434*cfb92d14SAndroid Build Coastguard Worker 'MaxTxAttempts': '2' 3435*cfb92d14SAndroid Build Coastguard Worker 'RecursionDesired': 'no' 3436*cfb92d14SAndroid Build Coastguard Worker } 3437*cfb92d14SAndroid Build Coastguard Worker """ 3438*cfb92d14SAndroid Build Coastguard Worker cmd = f'dns config' 3439*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3440*cfb92d14SAndroid Build Coastguard Worker output = self._expect_command_output() 3441*cfb92d14SAndroid Build Coastguard Worker config = {} 3442*cfb92d14SAndroid Build Coastguard Worker for line in output: 3443*cfb92d14SAndroid Build Coastguard Worker k, v = line.split(': ') 3444*cfb92d14SAndroid Build Coastguard Worker config[k] = v 3445*cfb92d14SAndroid Build Coastguard Worker return config 3446*cfb92d14SAndroid Build Coastguard Worker 3447*cfb92d14SAndroid Build Coastguard Worker def dns_set_config(self, config): 3448*cfb92d14SAndroid Build Coastguard Worker cmd = f'dns config {config}' 3449*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3450*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3451*cfb92d14SAndroid Build Coastguard Worker 3452*cfb92d14SAndroid Build Coastguard Worker def dns_resolve(self, hostname, server=None, port=53): 3453*cfb92d14SAndroid Build Coastguard Worker cmd = f'dns resolve {hostname}' 3454*cfb92d14SAndroid Build Coastguard Worker if server is not None: 3455*cfb92d14SAndroid Build Coastguard Worker cmd += f' {server} {port}' 3456*cfb92d14SAndroid Build Coastguard Worker 3457*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3458*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(10) 3459*cfb92d14SAndroid Build Coastguard Worker output = self._expect_command_output() 3460*cfb92d14SAndroid Build Coastguard Worker dns_resp = output[0] 3461*cfb92d14SAndroid Build Coastguard Worker # example output: "DNS response for host1.default.service.arpa. - fd00:db8:0:0:fd3d:d471:1e8c:b60 TTL:7190 " 3462*cfb92d14SAndroid Build Coastguard Worker # " fd00:db8:0:0:0:ff:fe00:9000 TTL:7190" 3463*cfb92d14SAndroid Build Coastguard Worker addrs = dns_resp.strip().split(' - ')[1].split(' ') 3464*cfb92d14SAndroid Build Coastguard Worker ip = [item.strip() for item in addrs[::2]] 3465*cfb92d14SAndroid Build Coastguard Worker ttl = [int(item.split('TTL:')[1]) for item in addrs[1::2]] 3466*cfb92d14SAndroid Build Coastguard Worker 3467*cfb92d14SAndroid Build Coastguard Worker return list(zip(ip, ttl)) 3468*cfb92d14SAndroid Build Coastguard Worker 3469*cfb92d14SAndroid Build Coastguard Worker def _parse_dns_service_info(self, output): 3470*cfb92d14SAndroid Build Coastguard Worker # Example of `output` 3471*cfb92d14SAndroid Build Coastguard Worker # Port:22222, Priority:2, Weight:2, TTL:7155 3472*cfb92d14SAndroid Build Coastguard Worker # Host:host2.default.service.arpa. 3473*cfb92d14SAndroid Build Coastguard Worker # HostAddress:0:0:0:0:0:0:0:0 TTL:0 3474*cfb92d14SAndroid Build Coastguard Worker # TXT:[a=00, b=02bb] TTL:7155 3475*cfb92d14SAndroid Build Coastguard Worker 3476*cfb92d14SAndroid Build Coastguard Worker m = re.match( 3477*cfb92d14SAndroid Build Coastguard Worker r'.*Port:(\d+), Priority:(\d+), Weight:(\d+), TTL:(\d+)\s+Host:(.*?)\s+HostAddress:(\S+) TTL:(\d+)\s+TXT:\[(.*?)\] TTL:(\d+)', 3478*cfb92d14SAndroid Build Coastguard Worker '\r'.join(output)) 3479*cfb92d14SAndroid Build Coastguard Worker if not m: 3480*cfb92d14SAndroid Build Coastguard Worker return {} 3481*cfb92d14SAndroid Build Coastguard Worker port, priority, weight, srv_ttl, hostname, address, aaaa_ttl, txt_data, txt_ttl = m.groups() 3482*cfb92d14SAndroid Build Coastguard Worker return { 3483*cfb92d14SAndroid Build Coastguard Worker 'port': int(port), 3484*cfb92d14SAndroid Build Coastguard Worker 'priority': int(priority), 3485*cfb92d14SAndroid Build Coastguard Worker 'weight': int(weight), 3486*cfb92d14SAndroid Build Coastguard Worker 'host': hostname, 3487*cfb92d14SAndroid Build Coastguard Worker 'address': address, 3488*cfb92d14SAndroid Build Coastguard Worker 'txt_data': txt_data, 3489*cfb92d14SAndroid Build Coastguard Worker 'srv_ttl': int(srv_ttl), 3490*cfb92d14SAndroid Build Coastguard Worker 'txt_ttl': int(txt_ttl), 3491*cfb92d14SAndroid Build Coastguard Worker 'aaaa_ttl': int(aaaa_ttl), 3492*cfb92d14SAndroid Build Coastguard Worker } 3493*cfb92d14SAndroid Build Coastguard Worker 3494*cfb92d14SAndroid Build Coastguard Worker def dns_resolve_service(self, instance, service, server=None, port=53): 3495*cfb92d14SAndroid Build Coastguard Worker """ 3496*cfb92d14SAndroid Build Coastguard Worker Resolves the service instance and returns the instance information as a dict. 3497*cfb92d14SAndroid Build Coastguard Worker 3498*cfb92d14SAndroid Build Coastguard Worker Example return value: 3499*cfb92d14SAndroid Build Coastguard Worker { 3500*cfb92d14SAndroid Build Coastguard Worker 'port': 12345, 3501*cfb92d14SAndroid Build Coastguard Worker 'priority': 0, 3502*cfb92d14SAndroid Build Coastguard Worker 'weight': 0, 3503*cfb92d14SAndroid Build Coastguard Worker 'host': 'ins1._ipps._tcp.default.service.arpa.', 3504*cfb92d14SAndroid Build Coastguard Worker 'address': '2001::1', 3505*cfb92d14SAndroid Build Coastguard Worker 'txt_data': 'a=00, b=02bb', 3506*cfb92d14SAndroid Build Coastguard Worker 'srv_ttl': 7100, 3507*cfb92d14SAndroid Build Coastguard Worker 'txt_ttl': 7100, 3508*cfb92d14SAndroid Build Coastguard Worker 'aaaa_ttl': 7100, 3509*cfb92d14SAndroid Build Coastguard Worker } 3510*cfb92d14SAndroid Build Coastguard Worker """ 3511*cfb92d14SAndroid Build Coastguard Worker instance = self._escape_escapable(instance) 3512*cfb92d14SAndroid Build Coastguard Worker cmd = f'dns service {instance} {service}' 3513*cfb92d14SAndroid Build Coastguard Worker if server is not None: 3514*cfb92d14SAndroid Build Coastguard Worker cmd += f' {server} {port}' 3515*cfb92d14SAndroid Build Coastguard Worker 3516*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3517*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(10) 3518*cfb92d14SAndroid Build Coastguard Worker output = self._expect_command_output() 3519*cfb92d14SAndroid Build Coastguard Worker info = self._parse_dns_service_info(output) 3520*cfb92d14SAndroid Build Coastguard Worker if not info: 3521*cfb92d14SAndroid Build Coastguard Worker raise Exception('dns resolve service failed: %s.%s' % (instance, service)) 3522*cfb92d14SAndroid Build Coastguard Worker return info 3523*cfb92d14SAndroid Build Coastguard Worker 3524*cfb92d14SAndroid Build Coastguard Worker @staticmethod 3525*cfb92d14SAndroid Build Coastguard Worker def __parse_hex_string(hexstr: str) -> bytes: 3526*cfb92d14SAndroid Build Coastguard Worker assert (len(hexstr) % 2 == 0) 3527*cfb92d14SAndroid Build Coastguard Worker return bytes(int(hexstr[i:i + 2], 16) for i in range(0, len(hexstr), 2)) 3528*cfb92d14SAndroid Build Coastguard Worker 3529*cfb92d14SAndroid Build Coastguard Worker def dns_browse(self, service_name, server=None, port=53): 3530*cfb92d14SAndroid Build Coastguard Worker """ 3531*cfb92d14SAndroid Build Coastguard Worker Browse the service and returns the instances. 3532*cfb92d14SAndroid Build Coastguard Worker 3533*cfb92d14SAndroid Build Coastguard Worker Example return value: 3534*cfb92d14SAndroid Build Coastguard Worker { 3535*cfb92d14SAndroid Build Coastguard Worker 'ins1': { 3536*cfb92d14SAndroid Build Coastguard Worker 'port': 12345, 3537*cfb92d14SAndroid Build Coastguard Worker 'priority': 1, 3538*cfb92d14SAndroid Build Coastguard Worker 'weight': 1, 3539*cfb92d14SAndroid Build Coastguard Worker 'host': 'ins1._ipps._tcp.default.service.arpa.', 3540*cfb92d14SAndroid Build Coastguard Worker 'address': '2001::1', 3541*cfb92d14SAndroid Build Coastguard Worker 'txt_data': 'a=00, b=11cf', 3542*cfb92d14SAndroid Build Coastguard Worker 'srv_ttl': 7100, 3543*cfb92d14SAndroid Build Coastguard Worker 'txt_ttl': 7100, 3544*cfb92d14SAndroid Build Coastguard Worker 'aaaa_ttl': 7100, 3545*cfb92d14SAndroid Build Coastguard Worker }, 3546*cfb92d14SAndroid Build Coastguard Worker 'ins2': { 3547*cfb92d14SAndroid Build Coastguard Worker 'port': 12345, 3548*cfb92d14SAndroid Build Coastguard Worker 'priority': 2, 3549*cfb92d14SAndroid Build Coastguard Worker 'weight': 2, 3550*cfb92d14SAndroid Build Coastguard Worker 'host': 'ins2._ipps._tcp.default.service.arpa.', 3551*cfb92d14SAndroid Build Coastguard Worker 'address': '2001::2', 3552*cfb92d14SAndroid Build Coastguard Worker 'txt_data': 'a=01, b=23dd', 3553*cfb92d14SAndroid Build Coastguard Worker 'srv_ttl': 7100, 3554*cfb92d14SAndroid Build Coastguard Worker 'txt_ttl': 7100, 3555*cfb92d14SAndroid Build Coastguard Worker 'aaaa_ttl': 7100, 3556*cfb92d14SAndroid Build Coastguard Worker } 3557*cfb92d14SAndroid Build Coastguard Worker } 3558*cfb92d14SAndroid Build Coastguard Worker """ 3559*cfb92d14SAndroid Build Coastguard Worker cmd = f'dns browse {service_name}' 3560*cfb92d14SAndroid Build Coastguard Worker if server is not None: 3561*cfb92d14SAndroid Build Coastguard Worker cmd += f' {server} {port}' 3562*cfb92d14SAndroid Build Coastguard Worker 3563*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3564*cfb92d14SAndroid Build Coastguard Worker self.simulator.go(10) 3565*cfb92d14SAndroid Build Coastguard Worker output = self._expect_command_output() 3566*cfb92d14SAndroid Build Coastguard Worker 3567*cfb92d14SAndroid Build Coastguard Worker # Example output: 3568*cfb92d14SAndroid Build Coastguard Worker # DNS browse response for _ipps._tcp.default.service.arpa. 3569*cfb92d14SAndroid Build Coastguard Worker # ins2 3570*cfb92d14SAndroid Build Coastguard Worker # Port:22222, Priority:2, Weight:2, TTL:7175 3571*cfb92d14SAndroid Build Coastguard Worker # Host:host2.default.service.arpa. 3572*cfb92d14SAndroid Build Coastguard Worker # HostAddress:fd00:db8:0:0:3205:28dd:5b87:6a63 TTL:7175 3573*cfb92d14SAndroid Build Coastguard Worker # TXT:[a=00, b=11cf] TTL:7175 3574*cfb92d14SAndroid Build Coastguard Worker # ins1 3575*cfb92d14SAndroid Build Coastguard Worker # Port:11111, Priority:1, Weight:1, TTL:7170 3576*cfb92d14SAndroid Build Coastguard Worker # Host:host1.default.service.arpa. 3577*cfb92d14SAndroid Build Coastguard Worker # HostAddress:fd00:db8:0:0:39f4:d9:eb4f:778 TTL:7170 3578*cfb92d14SAndroid Build Coastguard Worker # TXT:[a=01, b=23dd] TTL:7170 3579*cfb92d14SAndroid Build Coastguard Worker # Done 3580*cfb92d14SAndroid Build Coastguard Worker 3581*cfb92d14SAndroid Build Coastguard Worker result = {} 3582*cfb92d14SAndroid Build Coastguard Worker index = 1 # skip first line 3583*cfb92d14SAndroid Build Coastguard Worker while index < len(output): 3584*cfb92d14SAndroid Build Coastguard Worker ins = output[index].strip() 3585*cfb92d14SAndroid Build Coastguard Worker result[ins] = self._parse_dns_service_info(output[index + 1:index + 6]) 3586*cfb92d14SAndroid Build Coastguard Worker index = index + (5 if result[ins] else 1) 3587*cfb92d14SAndroid Build Coastguard Worker return result 3588*cfb92d14SAndroid Build Coastguard Worker 3589*cfb92d14SAndroid Build Coastguard Worker def set_mliid(self, mliid: str): 3590*cfb92d14SAndroid Build Coastguard Worker cmd = f'mliid {mliid}' 3591*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3592*cfb92d14SAndroid Build Coastguard Worker self._expect_command_output() 3593*cfb92d14SAndroid Build Coastguard Worker 3594*cfb92d14SAndroid Build Coastguard Worker def history_netinfo(self, num_entries=0): 3595*cfb92d14SAndroid Build Coastguard Worker """ 3596*cfb92d14SAndroid Build Coastguard Worker Get the `netinfo` history list, parse each entry and return 3597*cfb92d14SAndroid Build Coastguard Worker a list of dictionary (string key and string value) entries. 3598*cfb92d14SAndroid Build Coastguard Worker 3599*cfb92d14SAndroid Build Coastguard Worker Example of return value: 3600*cfb92d14SAndroid Build Coastguard Worker [ 3601*cfb92d14SAndroid Build Coastguard Worker { 3602*cfb92d14SAndroid Build Coastguard Worker 'age': '00:00:00.000 ago', 3603*cfb92d14SAndroid Build Coastguard Worker 'role': 'disabled', 3604*cfb92d14SAndroid Build Coastguard Worker 'mode': 'rdn', 3605*cfb92d14SAndroid Build Coastguard Worker 'rloc16': '0x7400', 3606*cfb92d14SAndroid Build Coastguard Worker 'partition-id': '1318093703' 3607*cfb92d14SAndroid Build Coastguard Worker }, 3608*cfb92d14SAndroid Build Coastguard Worker { 3609*cfb92d14SAndroid Build Coastguard Worker 'age': '00:00:02.588 ago', 3610*cfb92d14SAndroid Build Coastguard Worker 'role': 'leader', 3611*cfb92d14SAndroid Build Coastguard Worker 'mode': 'rdn', 3612*cfb92d14SAndroid Build Coastguard Worker 'rloc16': '0x7400', 3613*cfb92d14SAndroid Build Coastguard Worker 'partition-id': '1318093703' 3614*cfb92d14SAndroid Build Coastguard Worker } 3615*cfb92d14SAndroid Build Coastguard Worker ] 3616*cfb92d14SAndroid Build Coastguard Worker """ 3617*cfb92d14SAndroid Build Coastguard Worker cmd = f'history netinfo list {num_entries}' 3618*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3619*cfb92d14SAndroid Build Coastguard Worker output = self._expect_command_output() 3620*cfb92d14SAndroid Build Coastguard Worker netinfos = [] 3621*cfb92d14SAndroid Build Coastguard Worker for entry in output: 3622*cfb92d14SAndroid Build Coastguard Worker netinfo = {} 3623*cfb92d14SAndroid Build Coastguard Worker age, info = entry.split(' -> ') 3624*cfb92d14SAndroid Build Coastguard Worker netinfo['age'] = age 3625*cfb92d14SAndroid Build Coastguard Worker for item in info.split(' '): 3626*cfb92d14SAndroid Build Coastguard Worker k, v = item.split(':') 3627*cfb92d14SAndroid Build Coastguard Worker netinfo[k] = v 3628*cfb92d14SAndroid Build Coastguard Worker netinfos.append(netinfo) 3629*cfb92d14SAndroid Build Coastguard Worker return netinfos 3630*cfb92d14SAndroid Build Coastguard Worker 3631*cfb92d14SAndroid Build Coastguard Worker def history_rx(self, num_entries=0): 3632*cfb92d14SAndroid Build Coastguard Worker """ 3633*cfb92d14SAndroid Build Coastguard Worker Get the IPv6 RX history list, parse each entry and return 3634*cfb92d14SAndroid Build Coastguard Worker a list of dictionary (string key and string value) entries. 3635*cfb92d14SAndroid Build Coastguard Worker 3636*cfb92d14SAndroid Build Coastguard Worker Example of return value: 3637*cfb92d14SAndroid Build Coastguard Worker [ 3638*cfb92d14SAndroid Build Coastguard Worker { 3639*cfb92d14SAndroid Build Coastguard Worker 'age': '00:00:01.999', 3640*cfb92d14SAndroid Build Coastguard Worker 'type': 'ICMP6(EchoReqst)', 3641*cfb92d14SAndroid Build Coastguard Worker 'len': '16', 3642*cfb92d14SAndroid Build Coastguard Worker 'sec': 'yes', 3643*cfb92d14SAndroid Build Coastguard Worker 'prio': 'norm', 3644*cfb92d14SAndroid Build Coastguard Worker 'rss': '-20', 3645*cfb92d14SAndroid Build Coastguard Worker 'from': '0xac00', 3646*cfb92d14SAndroid Build Coastguard Worker 'radio': '15.4', 3647*cfb92d14SAndroid Build Coastguard Worker 'src': '[fd00:db8:0:0:2cfa:fd61:58a9:f0aa]:0', 3648*cfb92d14SAndroid Build Coastguard Worker 'dst': '[fd00:db8:0:0:ed7e:2d04:e543:eba5]:0', 3649*cfb92d14SAndroid Build Coastguard Worker } 3650*cfb92d14SAndroid Build Coastguard Worker ] 3651*cfb92d14SAndroid Build Coastguard Worker """ 3652*cfb92d14SAndroid Build Coastguard Worker cmd = f'history rx list {num_entries}' 3653*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3654*cfb92d14SAndroid Build Coastguard Worker return self._parse_history_rx_tx_ouput(self._expect_command_output()) 3655*cfb92d14SAndroid Build Coastguard Worker 3656*cfb92d14SAndroid Build Coastguard Worker def history_tx(self, num_entries=0): 3657*cfb92d14SAndroid Build Coastguard Worker """ 3658*cfb92d14SAndroid Build Coastguard Worker Get the IPv6 TX history list, parse each entry and return 3659*cfb92d14SAndroid Build Coastguard Worker a list of dictionary (string key and string value) entries. 3660*cfb92d14SAndroid Build Coastguard Worker 3661*cfb92d14SAndroid Build Coastguard Worker Example of return value: 3662*cfb92d14SAndroid Build Coastguard Worker [ 3663*cfb92d14SAndroid Build Coastguard Worker { 3664*cfb92d14SAndroid Build Coastguard Worker 'age': '00:00:01.999', 3665*cfb92d14SAndroid Build Coastguard Worker 'type': 'ICMP6(EchoReply)', 3666*cfb92d14SAndroid Build Coastguard Worker 'len': '16', 3667*cfb92d14SAndroid Build Coastguard Worker 'sec': 'yes', 3668*cfb92d14SAndroid Build Coastguard Worker 'prio': 'norm', 3669*cfb92d14SAndroid Build Coastguard Worker 'to': '0xac00', 3670*cfb92d14SAndroid Build Coastguard Worker 'tx-success': 'yes', 3671*cfb92d14SAndroid Build Coastguard Worker 'radio': '15.4', 3672*cfb92d14SAndroid Build Coastguard Worker 'src': '[fd00:db8:0:0:ed7e:2d04:e543:eba5]:0', 3673*cfb92d14SAndroid Build Coastguard Worker 'dst': '[fd00:db8:0:0:2cfa:fd61:58a9:f0aa]:0', 3674*cfb92d14SAndroid Build Coastguard Worker 3675*cfb92d14SAndroid Build Coastguard Worker } 3676*cfb92d14SAndroid Build Coastguard Worker ] 3677*cfb92d14SAndroid Build Coastguard Worker """ 3678*cfb92d14SAndroid Build Coastguard Worker cmd = f'history tx list {num_entries}' 3679*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3680*cfb92d14SAndroid Build Coastguard Worker return self._parse_history_rx_tx_ouput(self._expect_command_output()) 3681*cfb92d14SAndroid Build Coastguard Worker 3682*cfb92d14SAndroid Build Coastguard Worker def _parse_history_rx_tx_ouput(self, lines): 3683*cfb92d14SAndroid Build Coastguard Worker rxtx_list = [] 3684*cfb92d14SAndroid Build Coastguard Worker for line in lines: 3685*cfb92d14SAndroid Build Coastguard Worker if line.strip().startswith('type:'): 3686*cfb92d14SAndroid Build Coastguard Worker for item in line.strip().split(' '): 3687*cfb92d14SAndroid Build Coastguard Worker k, v = item.split(':') 3688*cfb92d14SAndroid Build Coastguard Worker entry[k] = v 3689*cfb92d14SAndroid Build Coastguard Worker elif line.strip().startswith('src:'): 3690*cfb92d14SAndroid Build Coastguard Worker entry['src'] = line[4:] 3691*cfb92d14SAndroid Build Coastguard Worker elif line.strip().startswith('dst:'): 3692*cfb92d14SAndroid Build Coastguard Worker entry['dst'] = line[4:] 3693*cfb92d14SAndroid Build Coastguard Worker rxtx_list.append(entry) 3694*cfb92d14SAndroid Build Coastguard Worker else: 3695*cfb92d14SAndroid Build Coastguard Worker entry = {} 3696*cfb92d14SAndroid Build Coastguard Worker entry['age'] = line 3697*cfb92d14SAndroid Build Coastguard Worker 3698*cfb92d14SAndroid Build Coastguard Worker return rxtx_list 3699*cfb92d14SAndroid Build Coastguard Worker 3700*cfb92d14SAndroid Build Coastguard Worker def set_router_id_range(self, min_router_id: int, max_router_id: int): 3701*cfb92d14SAndroid Build Coastguard Worker cmd = f'routeridrange {min_router_id} {max_router_id}' 3702*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3703*cfb92d14SAndroid Build Coastguard Worker self._expect_command_output() 3704*cfb92d14SAndroid Build Coastguard Worker 3705*cfb92d14SAndroid Build Coastguard Worker def get_router_id_range(self): 3706*cfb92d14SAndroid Build Coastguard Worker cmd = 'routeridrange' 3707*cfb92d14SAndroid Build Coastguard Worker self.send_command(cmd) 3708*cfb92d14SAndroid Build Coastguard Worker line = self._expect_command_output()[0] 3709*cfb92d14SAndroid Build Coastguard Worker return [int(item) for item in line.split()] 3710*cfb92d14SAndroid Build Coastguard Worker 3711*cfb92d14SAndroid Build Coastguard Worker def get_channel_monitor_info(self) -> Dict: 3712*cfb92d14SAndroid Build Coastguard Worker """ 3713*cfb92d14SAndroid Build Coastguard Worker Returns: 3714*cfb92d14SAndroid Build Coastguard Worker Dict of channel monitor info, e.g. 3715*cfb92d14SAndroid Build Coastguard Worker {'enabled': '1', 3716*cfb92d14SAndroid Build Coastguard Worker 'interval': '41000', 3717*cfb92d14SAndroid Build Coastguard Worker 'threshold': '-75', 3718*cfb92d14SAndroid Build Coastguard Worker 'window': '960', 3719*cfb92d14SAndroid Build Coastguard Worker 'count': '985', 3720*cfb92d14SAndroid Build Coastguard Worker 'occupancies': { 3721*cfb92d14SAndroid Build Coastguard Worker '11': '0.00%', 3722*cfb92d14SAndroid Build Coastguard Worker '12': '3.50%', 3723*cfb92d14SAndroid Build Coastguard Worker '13': '9.89%', 3724*cfb92d14SAndroid Build Coastguard Worker '14': '15.36%', 3725*cfb92d14SAndroid Build Coastguard Worker '15': '20.02%', 3726*cfb92d14SAndroid Build Coastguard Worker '16': '21.95%', 3727*cfb92d14SAndroid Build Coastguard Worker '17': '32.71%', 3728*cfb92d14SAndroid Build Coastguard Worker '18': '35.76%', 3729*cfb92d14SAndroid Build Coastguard Worker '19': '37.97%', 3730*cfb92d14SAndroid Build Coastguard Worker '20': '43.68%', 3731*cfb92d14SAndroid Build Coastguard Worker '21': '48.95%', 3732*cfb92d14SAndroid Build Coastguard Worker '22': '54.05%', 3733*cfb92d14SAndroid Build Coastguard Worker '23': '58.65%', 3734*cfb92d14SAndroid Build Coastguard Worker '24': '68.26%', 3735*cfb92d14SAndroid Build Coastguard Worker '25': '66.73%', 3736*cfb92d14SAndroid Build Coastguard Worker '26': '73.12%' 3737*cfb92d14SAndroid Build Coastguard Worker } 3738*cfb92d14SAndroid Build Coastguard Worker } 3739*cfb92d14SAndroid Build Coastguard Worker """ 3740*cfb92d14SAndroid Build Coastguard Worker config = {} 3741*cfb92d14SAndroid Build Coastguard Worker self.send_command('channel monitor') 3742*cfb92d14SAndroid Build Coastguard Worker 3743*cfb92d14SAndroid Build Coastguard Worker for line in self._expect_results(r'\S+'): 3744*cfb92d14SAndroid Build Coastguard Worker if re.match(r'.*:\s.*', line): 3745*cfb92d14SAndroid Build Coastguard Worker key, val = line.split(':') 3746*cfb92d14SAndroid Build Coastguard Worker config.update({key: val.strip()}) 3747*cfb92d14SAndroid Build Coastguard Worker elif re.match(r'.*:', line): # occupancy 3748*cfb92d14SAndroid Build Coastguard Worker occ_key, val = line.split(':') 3749*cfb92d14SAndroid Build Coastguard Worker val = {} 3750*cfb92d14SAndroid Build Coastguard Worker config.update({occ_key: val}) 3751*cfb92d14SAndroid Build Coastguard Worker elif 'busy' in line: 3752*cfb92d14SAndroid Build Coastguard Worker # channel occupancies 3753*cfb92d14SAndroid Build Coastguard Worker key = line.split()[1] 3754*cfb92d14SAndroid Build Coastguard Worker val = line.split()[3] 3755*cfb92d14SAndroid Build Coastguard Worker config[occ_key].update({key: val}) 3756*cfb92d14SAndroid Build Coastguard Worker return config 3757*cfb92d14SAndroid Build Coastguard Worker 3758*cfb92d14SAndroid Build Coastguard Worker def set_channel_manager_auto_enable(self, enable: bool): 3759*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'channel manager auto {int(enable)}') 3760*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3761*cfb92d14SAndroid Build Coastguard Worker 3762*cfb92d14SAndroid Build Coastguard Worker def set_channel_manager_autocsl_enable(self, enable: bool): 3763*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'channel manager autocsl {int(enable)}') 3764*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3765*cfb92d14SAndroid Build Coastguard Worker 3766*cfb92d14SAndroid Build Coastguard Worker def set_channel_manager_supported(self, channel_mask: int): 3767*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'channel manager supported {int(channel_mask)}') 3768*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3769*cfb92d14SAndroid Build Coastguard Worker 3770*cfb92d14SAndroid Build Coastguard Worker def set_channel_manager_favored(self, channel_mask: int): 3771*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'channel manager favored {int(channel_mask)}') 3772*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3773*cfb92d14SAndroid Build Coastguard Worker 3774*cfb92d14SAndroid Build Coastguard Worker def set_channel_manager_interval(self, interval: int): 3775*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'channel manager interval {interval}') 3776*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3777*cfb92d14SAndroid Build Coastguard Worker 3778*cfb92d14SAndroid Build Coastguard Worker def set_channel_manager_cca_threshold(self, hex_value: str): 3779*cfb92d14SAndroid Build Coastguard Worker self.send_command(f'channel manager threshold {hex_value}') 3780*cfb92d14SAndroid Build Coastguard Worker self._expect_done() 3781*cfb92d14SAndroid Build Coastguard Worker 3782*cfb92d14SAndroid Build Coastguard Worker def get_channel_manager_config(self): 3783*cfb92d14SAndroid Build Coastguard Worker self.send_command('channel manager') 3784*cfb92d14SAndroid Build Coastguard Worker return self._expect_key_value_pairs(r'\S+') 3785*cfb92d14SAndroid Build Coastguard Worker 3786*cfb92d14SAndroid Build Coastguard Worker 3787*cfb92d14SAndroid Build Coastguard Workerclass Node(NodeImpl, OtCli): 3788*cfb92d14SAndroid Build Coastguard Worker pass 3789*cfb92d14SAndroid Build Coastguard Worker 3790*cfb92d14SAndroid Build Coastguard Worker 3791*cfb92d14SAndroid Build Coastguard Workerclass LinuxHost(): 3792*cfb92d14SAndroid Build Coastguard Worker PING_RESPONSE_PATTERN = re.compile(r'\d+ bytes from .*:.*') 3793*cfb92d14SAndroid Build Coastguard Worker ETH_DEV = config.BACKBONE_IFNAME 3794*cfb92d14SAndroid Build Coastguard Worker 3795*cfb92d14SAndroid Build Coastguard Worker def enable_ether(self): 3796*cfb92d14SAndroid Build Coastguard Worker """Enable the ethernet interface. 3797*cfb92d14SAndroid Build Coastguard Worker """ 3798*cfb92d14SAndroid Build Coastguard Worker 3799*cfb92d14SAndroid Build Coastguard Worker self.bash(f'ip link set {self.ETH_DEV} up') 3800*cfb92d14SAndroid Build Coastguard Worker 3801*cfb92d14SAndroid Build Coastguard Worker def disable_ether(self): 3802*cfb92d14SAndroid Build Coastguard Worker """Disable the ethernet interface. 3803*cfb92d14SAndroid Build Coastguard Worker """ 3804*cfb92d14SAndroid Build Coastguard Worker 3805*cfb92d14SAndroid Build Coastguard Worker self.bash(f'ip link set {self.ETH_DEV} down') 3806*cfb92d14SAndroid Build Coastguard Worker 3807*cfb92d14SAndroid Build Coastguard Worker def get_ether_addrs(self, ipv4=False, ipv6=True): 3808*cfb92d14SAndroid Build Coastguard Worker output = self.bash(f'ip addr list dev {self.ETH_DEV}') 3809*cfb92d14SAndroid Build Coastguard Worker 3810*cfb92d14SAndroid Build Coastguard Worker addrs = [] 3811*cfb92d14SAndroid Build Coastguard Worker for line in output: 3812*cfb92d14SAndroid Build Coastguard Worker # line examples: 3813*cfb92d14SAndroid Build Coastguard Worker # "inet6 fe80::42:c0ff:fea8:903/64 scope link" 3814*cfb92d14SAndroid Build Coastguard Worker # "inet 192.168.9.1/24 brd 192.168.9.255 scope global eth0" 3815*cfb92d14SAndroid Build Coastguard Worker line = line.strip().split() 3816*cfb92d14SAndroid Build Coastguard Worker 3817*cfb92d14SAndroid Build Coastguard Worker if not line or not line[0].startswith('inet'): 3818*cfb92d14SAndroid Build Coastguard Worker continue 3819*cfb92d14SAndroid Build Coastguard Worker if line[0] == 'inet' and not ipv4: 3820*cfb92d14SAndroid Build Coastguard Worker continue 3821*cfb92d14SAndroid Build Coastguard Worker if line[0] == 'inet6' and not ipv6: 3822*cfb92d14SAndroid Build Coastguard Worker continue 3823*cfb92d14SAndroid Build Coastguard Worker 3824*cfb92d14SAndroid Build Coastguard Worker addr = line[1] 3825*cfb92d14SAndroid Build Coastguard Worker if '/' in addr: 3826*cfb92d14SAndroid Build Coastguard Worker addr = addr.split('/')[0] 3827*cfb92d14SAndroid Build Coastguard Worker addrs.append(addr) 3828*cfb92d14SAndroid Build Coastguard Worker 3829*cfb92d14SAndroid Build Coastguard Worker logging.debug('%s: get_ether_addrs: %r', self, addrs) 3830*cfb92d14SAndroid Build Coastguard Worker return addrs 3831*cfb92d14SAndroid Build Coastguard Worker 3832*cfb92d14SAndroid Build Coastguard Worker def get_ether_mac(self): 3833*cfb92d14SAndroid Build Coastguard Worker output = self.bash(f'ip addr list dev {self.ETH_DEV}') 3834*cfb92d14SAndroid Build Coastguard Worker for line in output: 3835*cfb92d14SAndroid Build Coastguard Worker # link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 3836*cfb92d14SAndroid Build Coastguard Worker line = line.strip().split() 3837*cfb92d14SAndroid Build Coastguard Worker if line and line[0] == 'link/ether': 3838*cfb92d14SAndroid Build Coastguard Worker return line[1] 3839*cfb92d14SAndroid Build Coastguard Worker 3840*cfb92d14SAndroid Build Coastguard Worker assert False, output 3841*cfb92d14SAndroid Build Coastguard Worker 3842*cfb92d14SAndroid Build Coastguard Worker def add_ipmaddr_ether(self, ip: str): 3843*cfb92d14SAndroid Build Coastguard Worker cmd = f'python3 /app/third_party/openthread/repo/tests/scripts/thread-cert/mcast6.py {self.ETH_DEV} {ip} &' 3844*cfb92d14SAndroid Build Coastguard Worker self.bash(cmd) 3845*cfb92d14SAndroid Build Coastguard Worker 3846*cfb92d14SAndroid Build Coastguard Worker def ping_ether(self, ipaddr, num_responses=1, size=None, timeout=5, ttl=None, interface='eth0') -> int: 3847*cfb92d14SAndroid Build Coastguard Worker 3848*cfb92d14SAndroid Build Coastguard Worker cmd = f'ping -6 {ipaddr} -I {interface} -c {num_responses} -W {timeout}' 3849*cfb92d14SAndroid Build Coastguard Worker if size is not None: 3850*cfb92d14SAndroid Build Coastguard Worker cmd += f' -s {size}' 3851*cfb92d14SAndroid Build Coastguard Worker 3852*cfb92d14SAndroid Build Coastguard Worker if ttl is not None: 3853*cfb92d14SAndroid Build Coastguard Worker cmd += f' -t {ttl}' 3854*cfb92d14SAndroid Build Coastguard Worker 3855*cfb92d14SAndroid Build Coastguard Worker resp_count = 0 3856*cfb92d14SAndroid Build Coastguard Worker 3857*cfb92d14SAndroid Build Coastguard Worker try: 3858*cfb92d14SAndroid Build Coastguard Worker for line in self.bash(cmd): 3859*cfb92d14SAndroid Build Coastguard Worker if self.PING_RESPONSE_PATTERN.match(line): 3860*cfb92d14SAndroid Build Coastguard Worker resp_count += 1 3861*cfb92d14SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 3862*cfb92d14SAndroid Build Coastguard Worker pass 3863*cfb92d14SAndroid Build Coastguard Worker 3864*cfb92d14SAndroid Build Coastguard Worker return resp_count 3865*cfb92d14SAndroid Build Coastguard Worker 3866*cfb92d14SAndroid Build Coastguard Worker def get_ip6_address(self, address_type: config.ADDRESS_TYPE): 3867*cfb92d14SAndroid Build Coastguard Worker """Get specific type of IPv6 address configured on thread device. 3868*cfb92d14SAndroid Build Coastguard Worker 3869*cfb92d14SAndroid Build Coastguard Worker Args: 3870*cfb92d14SAndroid Build Coastguard Worker address_type: the config.ADDRESS_TYPE type of IPv6 address. 3871*cfb92d14SAndroid Build Coastguard Worker 3872*cfb92d14SAndroid Build Coastguard Worker Returns: 3873*cfb92d14SAndroid Build Coastguard Worker IPv6 address string. 3874*cfb92d14SAndroid Build Coastguard Worker """ 3875*cfb92d14SAndroid Build Coastguard Worker if address_type == config.ADDRESS_TYPE.BACKBONE_GUA: 3876*cfb92d14SAndroid Build Coastguard Worker return self._getBackboneGua() 3877*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.BACKBONE_LINK_LOCAL: 3878*cfb92d14SAndroid Build Coastguard Worker return self._getInfraLinkLocalAddress() 3879*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.ONLINK_ULA: 3880*cfb92d14SAndroid Build Coastguard Worker return self._getInfraUla() 3881*cfb92d14SAndroid Build Coastguard Worker elif address_type == config.ADDRESS_TYPE.ONLINK_GUA: 3882*cfb92d14SAndroid Build Coastguard Worker return self._getInfraGua() 3883*cfb92d14SAndroid Build Coastguard Worker else: 3884*cfb92d14SAndroid Build Coastguard Worker raise ValueError(f'unsupported address type: {address_type}') 3885*cfb92d14SAndroid Build Coastguard Worker 3886*cfb92d14SAndroid Build Coastguard Worker def _getBackboneGua(self) -> Optional[str]: 3887*cfb92d14SAndroid Build Coastguard Worker for addr in self.get_ether_addrs(): 3888*cfb92d14SAndroid Build Coastguard Worker if re.match(config.BACKBONE_PREFIX_REGEX_PATTERN, addr, re.I): 3889*cfb92d14SAndroid Build Coastguard Worker return addr 3890*cfb92d14SAndroid Build Coastguard Worker 3891*cfb92d14SAndroid Build Coastguard Worker return None 3892*cfb92d14SAndroid Build Coastguard Worker 3893*cfb92d14SAndroid Build Coastguard Worker def _getInfraUla(self) -> Optional[str]: 3894*cfb92d14SAndroid Build Coastguard Worker """ Returns the ULA addresses autoconfigured on the infra link. 3895*cfb92d14SAndroid Build Coastguard Worker """ 3896*cfb92d14SAndroid Build Coastguard Worker addrs = [] 3897*cfb92d14SAndroid Build Coastguard Worker for addr in self.get_ether_addrs(): 3898*cfb92d14SAndroid Build Coastguard Worker if re.match(config.ONLINK_PREFIX_REGEX_PATTERN, addr, re.I): 3899*cfb92d14SAndroid Build Coastguard Worker addrs.append(addr) 3900*cfb92d14SAndroid Build Coastguard Worker 3901*cfb92d14SAndroid Build Coastguard Worker return addrs 3902*cfb92d14SAndroid Build Coastguard Worker 3903*cfb92d14SAndroid Build Coastguard Worker def _getInfraGua(self) -> Optional[str]: 3904*cfb92d14SAndroid Build Coastguard Worker """ Returns the GUA addresses autoconfigured on the infra link. 3905*cfb92d14SAndroid Build Coastguard Worker """ 3906*cfb92d14SAndroid Build Coastguard Worker 3907*cfb92d14SAndroid Build Coastguard Worker gua_prefix = config.ONLINK_GUA_PREFIX.split('::/')[0] 3908*cfb92d14SAndroid Build Coastguard Worker return [addr for addr in self.get_ether_addrs() if addr.startswith(gua_prefix)] 3909*cfb92d14SAndroid Build Coastguard Worker 3910*cfb92d14SAndroid Build Coastguard Worker def _getInfraLinkLocalAddress(self) -> Optional[str]: 3911*cfb92d14SAndroid Build Coastguard Worker """ Returns the link-local address autoconfigured on the infra link, which is started with "fe80". 3912*cfb92d14SAndroid Build Coastguard Worker """ 3913*cfb92d14SAndroid Build Coastguard Worker for addr in self.get_ether_addrs(): 3914*cfb92d14SAndroid Build Coastguard Worker if re.match(config.LINK_LOCAL_REGEX_PATTERN, addr, re.I): 3915*cfb92d14SAndroid Build Coastguard Worker return addr 3916*cfb92d14SAndroid Build Coastguard Worker 3917*cfb92d14SAndroid Build Coastguard Worker return None 3918*cfb92d14SAndroid Build Coastguard Worker 3919*cfb92d14SAndroid Build Coastguard Worker def ping(self, *args, **kwargs): 3920*cfb92d14SAndroid Build Coastguard Worker backbone = kwargs.pop('backbone', False) 3921*cfb92d14SAndroid Build Coastguard Worker if backbone: 3922*cfb92d14SAndroid Build Coastguard Worker return self.ping_ether(*args, **kwargs) 3923*cfb92d14SAndroid Build Coastguard Worker else: 3924*cfb92d14SAndroid Build Coastguard Worker return super().ping(*args, **kwargs) 3925*cfb92d14SAndroid Build Coastguard Worker 3926*cfb92d14SAndroid Build Coastguard Worker def udp_send_host(self, ipaddr, port, data, hop_limit=None): 3927*cfb92d14SAndroid Build Coastguard Worker if hop_limit is None: 3928*cfb92d14SAndroid Build Coastguard Worker if ipaddress.ip_address(ipaddr).is_multicast: 3929*cfb92d14SAndroid Build Coastguard Worker hop_limit = 10 3930*cfb92d14SAndroid Build Coastguard Worker else: 3931*cfb92d14SAndroid Build Coastguard Worker hop_limit = 64 3932*cfb92d14SAndroid Build Coastguard Worker cmd = f'python3 /app/third_party/openthread/repo/tests/scripts/thread-cert/udp_send_host.py {ipaddr} {port} "{data}" {hop_limit}' 3933*cfb92d14SAndroid Build Coastguard Worker self.bash(cmd) 3934*cfb92d14SAndroid Build Coastguard Worker 3935*cfb92d14SAndroid Build Coastguard Worker def add_ipmaddr(self, *args, **kwargs): 3936*cfb92d14SAndroid Build Coastguard Worker backbone = kwargs.pop('backbone', False) 3937*cfb92d14SAndroid Build Coastguard Worker if backbone: 3938*cfb92d14SAndroid Build Coastguard Worker return self.add_ipmaddr_ether(*args, **kwargs) 3939*cfb92d14SAndroid Build Coastguard Worker else: 3940*cfb92d14SAndroid Build Coastguard Worker return super().add_ipmaddr(*args, **kwargs) 3941*cfb92d14SAndroid Build Coastguard Worker 3942*cfb92d14SAndroid Build Coastguard Worker def ip_neighbors_flush(self): 3943*cfb92d14SAndroid Build Coastguard Worker # clear neigh cache on linux 3944*cfb92d14SAndroid Build Coastguard Worker self.bash(f'ip -6 neigh list dev {self.ETH_DEV}') 3945*cfb92d14SAndroid Build Coastguard Worker self.bash(f'ip -6 neigh flush nud all nud failed nud noarp dev {self.ETH_DEV}') 3946*cfb92d14SAndroid Build Coastguard Worker self.bash('ip -6 neigh list nud all dev %s | cut -d " " -f1 | sudo xargs -I{} ip -6 neigh delete {} dev %s' % 3947*cfb92d14SAndroid Build Coastguard Worker (self.ETH_DEV, self.ETH_DEV)) 3948*cfb92d14SAndroid Build Coastguard Worker self.bash(f'ip -6 neigh list dev {self.ETH_DEV}') 3949*cfb92d14SAndroid Build Coastguard Worker 3950*cfb92d14SAndroid Build Coastguard Worker def publish_mdns_service(self, instance_name, service_type, port, host_name, txt): 3951*cfb92d14SAndroid Build Coastguard Worker """Publish an mDNS service on the Ethernet. 3952*cfb92d14SAndroid Build Coastguard Worker 3953*cfb92d14SAndroid Build Coastguard Worker :param instance_name: the service instance name. 3954*cfb92d14SAndroid Build Coastguard Worker :param service_type: the service type in format of '<service_type>.<protocol>'. 3955*cfb92d14SAndroid Build Coastguard Worker :param port: the port the service is at. 3956*cfb92d14SAndroid Build Coastguard Worker :param host_name: the host name this service points to. The domain 3957*cfb92d14SAndroid Build Coastguard Worker should not be included. 3958*cfb92d14SAndroid Build Coastguard Worker :param txt: a dictionary containing the key-value pairs of the TXT record. 3959*cfb92d14SAndroid Build Coastguard Worker """ 3960*cfb92d14SAndroid Build Coastguard Worker txt_string = ' '.join([f'{key}={value}' for key, value in txt.items()]) 3961*cfb92d14SAndroid Build Coastguard Worker self.bash(f'avahi-publish -s {instance_name} {service_type} {port} -H {host_name}.local {txt_string} &') 3962*cfb92d14SAndroid Build Coastguard Worker 3963*cfb92d14SAndroid Build Coastguard Worker def publish_mdns_host(self, hostname, addresses): 3964*cfb92d14SAndroid Build Coastguard Worker """Publish an mDNS host on the Ethernet 3965*cfb92d14SAndroid Build Coastguard Worker 3966*cfb92d14SAndroid Build Coastguard Worker :param host_name: the host name this service points to. The domain 3967*cfb92d14SAndroid Build Coastguard Worker should not be included. 3968*cfb92d14SAndroid Build Coastguard Worker :param addresses: a list of strings representing the addresses to 3969*cfb92d14SAndroid Build Coastguard Worker be registered with the host. 3970*cfb92d14SAndroid Build Coastguard Worker """ 3971*cfb92d14SAndroid Build Coastguard Worker for address in addresses: 3972*cfb92d14SAndroid Build Coastguard Worker self.bash(f'avahi-publish -a {hostname}.local {address} &') 3973*cfb92d14SAndroid Build Coastguard Worker 3974*cfb92d14SAndroid Build Coastguard Worker def browse_mdns_services(self, name, timeout=2): 3975*cfb92d14SAndroid Build Coastguard Worker """ Browse mDNS services on the ethernet. 3976*cfb92d14SAndroid Build Coastguard Worker 3977*cfb92d14SAndroid Build Coastguard Worker :param name: the service type name in format of '<service-name>.<protocol>'. 3978*cfb92d14SAndroid Build Coastguard Worker :param timeout: timeout value in seconds before returning. 3979*cfb92d14SAndroid Build Coastguard Worker :return: A list of service instance names. 3980*cfb92d14SAndroid Build Coastguard Worker """ 3981*cfb92d14SAndroid Build Coastguard Worker 3982*cfb92d14SAndroid Build Coastguard Worker self.bash(f'dns-sd -Z {name} local. > /tmp/{name} 2>&1 &') 3983*cfb92d14SAndroid Build Coastguard Worker time.sleep(timeout) 3984*cfb92d14SAndroid Build Coastguard Worker self.bash('pkill dns-sd') 3985*cfb92d14SAndroid Build Coastguard Worker 3986*cfb92d14SAndroid Build Coastguard Worker instances = [] 3987*cfb92d14SAndroid Build Coastguard Worker for line in self.bash(f'cat /tmp/{name}', encoding='raw_unicode_escape'): 3988*cfb92d14SAndroid Build Coastguard Worker elements = line.split() 3989*cfb92d14SAndroid Build Coastguard Worker if len(elements) >= 3 and elements[0] == name and elements[1] == 'PTR': 3990*cfb92d14SAndroid Build Coastguard Worker instances.append(elements[2][:-len('.' + name)]) 3991*cfb92d14SAndroid Build Coastguard Worker return instances 3992*cfb92d14SAndroid Build Coastguard Worker 3993*cfb92d14SAndroid Build Coastguard Worker def discover_mdns_service(self, instance, name, host_name, timeout=2): 3994*cfb92d14SAndroid Build Coastguard Worker """ Discover/resolve the mDNS service on ethernet. 3995*cfb92d14SAndroid Build Coastguard Worker 3996*cfb92d14SAndroid Build Coastguard Worker :param instance: the service instance name. 3997*cfb92d14SAndroid Build Coastguard Worker :param name: the service name in format of '<service-name>.<protocol>'. 3998*cfb92d14SAndroid Build Coastguard Worker :param host_name: the host name this service points to. The domain 3999*cfb92d14SAndroid Build Coastguard Worker should not be included. 4000*cfb92d14SAndroid Build Coastguard Worker :param timeout: timeout value in seconds before returning. 4001*cfb92d14SAndroid Build Coastguard Worker :return: a dict of service properties or None. 4002*cfb92d14SAndroid Build Coastguard Worker 4003*cfb92d14SAndroid Build Coastguard Worker The return value is a dict with the same key/values of srp_server_get_service 4004*cfb92d14SAndroid Build Coastguard Worker except that we don't have a `deleted` field here. 4005*cfb92d14SAndroid Build Coastguard Worker """ 4006*cfb92d14SAndroid Build Coastguard Worker host_name_file = self.bash('mktemp')[0].strip() 4007*cfb92d14SAndroid Build Coastguard Worker service_data_file = self.bash('mktemp')[0].strip() 4008*cfb92d14SAndroid Build Coastguard Worker 4009*cfb92d14SAndroid Build Coastguard Worker self.bash(f'dns-sd -Z {name} local. > {service_data_file} 2>&1 &') 4010*cfb92d14SAndroid Build Coastguard Worker time.sleep(timeout) 4011*cfb92d14SAndroid Build Coastguard Worker 4012*cfb92d14SAndroid Build Coastguard Worker full_service_name = f'{instance}.{name}' 4013*cfb92d14SAndroid Build Coastguard Worker # When hostname is unspecified, extract hostname from browse result 4014*cfb92d14SAndroid Build Coastguard Worker if host_name is None: 4015*cfb92d14SAndroid Build Coastguard Worker for line in self.bash(f'cat {service_data_file}', encoding='raw_unicode_escape'): 4016*cfb92d14SAndroid Build Coastguard Worker elements = line.split() 4017*cfb92d14SAndroid Build Coastguard Worker if len(elements) >= 6 and elements[0] == full_service_name and elements[1] == 'SRV': 4018*cfb92d14SAndroid Build Coastguard Worker host_name = elements[5].split('.')[0] 4019*cfb92d14SAndroid Build Coastguard Worker break 4020*cfb92d14SAndroid Build Coastguard Worker 4021*cfb92d14SAndroid Build Coastguard Worker assert (host_name is not None) 4022*cfb92d14SAndroid Build Coastguard Worker self.bash(f'dns-sd -G v6 {host_name}.local. > {host_name_file} 2>&1 &') 4023*cfb92d14SAndroid Build Coastguard Worker time.sleep(timeout) 4024*cfb92d14SAndroid Build Coastguard Worker 4025*cfb92d14SAndroid Build Coastguard Worker self.bash('pkill dns-sd') 4026*cfb92d14SAndroid Build Coastguard Worker addresses = [] 4027*cfb92d14SAndroid Build Coastguard Worker service = {} 4028*cfb92d14SAndroid Build Coastguard Worker 4029*cfb92d14SAndroid Build Coastguard Worker logging.debug(self.bash(f'cat {host_name_file}', encoding='raw_unicode_escape')) 4030*cfb92d14SAndroid Build Coastguard Worker logging.debug(self.bash(f'cat {service_data_file}', encoding='raw_unicode_escape')) 4031*cfb92d14SAndroid Build Coastguard Worker 4032*cfb92d14SAndroid Build Coastguard Worker # example output in the host file: 4033*cfb92d14SAndroid Build Coastguard Worker # Timestamp A/R Flags if Hostname Address TTL 4034*cfb92d14SAndroid Build Coastguard Worker # 9:38:09.274 Add 23 48 my-host.local. 2001:0000:0000:0000:0000:0000:0000:0002%<0> 120 4035*cfb92d14SAndroid Build Coastguard Worker # 4036*cfb92d14SAndroid Build Coastguard Worker for line in self.bash(f'cat {host_name_file}', encoding='raw_unicode_escape'): 4037*cfb92d14SAndroid Build Coastguard Worker elements = line.split() 4038*cfb92d14SAndroid Build Coastguard Worker fullname = f'{host_name}.local.' 4039*cfb92d14SAndroid Build Coastguard Worker if fullname not in elements: 4040*cfb92d14SAndroid Build Coastguard Worker continue 4041*cfb92d14SAndroid Build Coastguard Worker if 'Add' not in elements: 4042*cfb92d14SAndroid Build Coastguard Worker continue 4043*cfb92d14SAndroid Build Coastguard Worker addresses.append(elements[elements.index(fullname) + 1].split('%')[0]) 4044*cfb92d14SAndroid Build Coastguard Worker 4045*cfb92d14SAndroid Build Coastguard Worker logging.debug(f'addresses of {host_name}: {addresses}') 4046*cfb92d14SAndroid Build Coastguard Worker 4047*cfb92d14SAndroid Build Coastguard Worker # example output of in the service file: 4048*cfb92d14SAndroid Build Coastguard Worker # _ipps._tcp PTR my-service._ipps._tcp 4049*cfb92d14SAndroid Build Coastguard Worker # my-service._ipps._tcp SRV 0 0 12345 my-host.local. ; Replace with unicast FQDN of target host 4050*cfb92d14SAndroid Build Coastguard Worker # my-service._ipps._tcp TXT "" 4051*cfb92d14SAndroid Build Coastguard Worker # 4052*cfb92d14SAndroid Build Coastguard Worker is_txt = False 4053*cfb92d14SAndroid Build Coastguard Worker txt = '' 4054*cfb92d14SAndroid Build Coastguard Worker for line in self.bash(f'cat {service_data_file}', encoding='raw_unicode_escape'): 4055*cfb92d14SAndroid Build Coastguard Worker elements = line.split() 4056*cfb92d14SAndroid Build Coastguard Worker if len(elements) >= 2 and elements[0] == full_service_name and elements[1] == 'TXT': 4057*cfb92d14SAndroid Build Coastguard Worker is_txt = True 4058*cfb92d14SAndroid Build Coastguard Worker if is_txt: 4059*cfb92d14SAndroid Build Coastguard Worker txt += line.strip() 4060*cfb92d14SAndroid Build Coastguard Worker if line.strip().endswith('"'): 4061*cfb92d14SAndroid Build Coastguard Worker is_txt = False 4062*cfb92d14SAndroid Build Coastguard Worker txt_dict = self.__parse_dns_sd_txt(txt) 4063*cfb92d14SAndroid Build Coastguard Worker logging.info(f'txt = {txt_dict}') 4064*cfb92d14SAndroid Build Coastguard Worker service['txt'] = txt_dict 4065*cfb92d14SAndroid Build Coastguard Worker 4066*cfb92d14SAndroid Build Coastguard Worker if not elements or elements[0] != full_service_name: 4067*cfb92d14SAndroid Build Coastguard Worker continue 4068*cfb92d14SAndroid Build Coastguard Worker if elements[1] == 'SRV': 4069*cfb92d14SAndroid Build Coastguard Worker service['fullname'] = elements[0] 4070*cfb92d14SAndroid Build Coastguard Worker service['instance'] = instance 4071*cfb92d14SAndroid Build Coastguard Worker service['name'] = name 4072*cfb92d14SAndroid Build Coastguard Worker service['priority'] = int(elements[2]) 4073*cfb92d14SAndroid Build Coastguard Worker service['weight'] = int(elements[3]) 4074*cfb92d14SAndroid Build Coastguard Worker service['port'] = int(elements[4]) 4075*cfb92d14SAndroid Build Coastguard Worker service['host_fullname'] = elements[5] 4076*cfb92d14SAndroid Build Coastguard Worker assert (service['host_fullname'] == f'{host_name}.local.') 4077*cfb92d14SAndroid Build Coastguard Worker service['host'] = host_name 4078*cfb92d14SAndroid Build Coastguard Worker service['addresses'] = addresses 4079*cfb92d14SAndroid Build Coastguard Worker return service or None 4080*cfb92d14SAndroid Build Coastguard Worker 4081*cfb92d14SAndroid Build Coastguard Worker def start_radvd_service(self, prefix, slaac): 4082*cfb92d14SAndroid Build Coastguard Worker self.bash("""cat >/etc/radvd.conf <<EOF 4083*cfb92d14SAndroid Build Coastguard Workerinterface eth0 4084*cfb92d14SAndroid Build Coastguard Worker{ 4085*cfb92d14SAndroid Build Coastguard Worker AdvSendAdvert on; 4086*cfb92d14SAndroid Build Coastguard Worker 4087*cfb92d14SAndroid Build Coastguard Worker AdvReachableTime 200; 4088*cfb92d14SAndroid Build Coastguard Worker AdvRetransTimer 200; 4089*cfb92d14SAndroid Build Coastguard Worker AdvDefaultLifetime 1800; 4090*cfb92d14SAndroid Build Coastguard Worker MinRtrAdvInterval 1200; 4091*cfb92d14SAndroid Build Coastguard Worker MaxRtrAdvInterval 1800; 4092*cfb92d14SAndroid Build Coastguard Worker AdvDefaultPreference low; 4093*cfb92d14SAndroid Build Coastguard Worker 4094*cfb92d14SAndroid Build Coastguard Worker prefix %s 4095*cfb92d14SAndroid Build Coastguard Worker { 4096*cfb92d14SAndroid Build Coastguard Worker AdvOnLink on; 4097*cfb92d14SAndroid Build Coastguard Worker AdvAutonomous %s; 4098*cfb92d14SAndroid Build Coastguard Worker AdvRouterAddr off; 4099*cfb92d14SAndroid Build Coastguard Worker AdvPreferredLifetime 1800; 4100*cfb92d14SAndroid Build Coastguard Worker AdvValidLifetime 1800; 4101*cfb92d14SAndroid Build Coastguard Worker }; 4102*cfb92d14SAndroid Build Coastguard Worker}; 4103*cfb92d14SAndroid Build Coastguard WorkerEOF 4104*cfb92d14SAndroid Build Coastguard Worker""" % (prefix, 'on' if slaac else 'off')) 4105*cfb92d14SAndroid Build Coastguard Worker self.bash('service radvd start') 4106*cfb92d14SAndroid Build Coastguard Worker self.bash('service radvd status') # Make sure radvd service is running 4107*cfb92d14SAndroid Build Coastguard Worker 4108*cfb92d14SAndroid Build Coastguard Worker def stop_radvd_service(self): 4109*cfb92d14SAndroid Build Coastguard Worker self.bash('service radvd stop') 4110*cfb92d14SAndroid Build Coastguard Worker 4111*cfb92d14SAndroid Build Coastguard Worker def kill_radvd_service(self): 4112*cfb92d14SAndroid Build Coastguard Worker self.bash('pkill radvd') 4113*cfb92d14SAndroid Build Coastguard Worker 4114*cfb92d14SAndroid Build Coastguard Worker def __parse_dns_sd_txt(self, line: str): 4115*cfb92d14SAndroid Build Coastguard Worker # Example TXT entry: 4116*cfb92d14SAndroid Build Coastguard Worker # "xp=\\000\\013\\184\\000\\000\\000\\000\\000" 4117*cfb92d14SAndroid Build Coastguard Worker txt = {} 4118*cfb92d14SAndroid Build Coastguard Worker for entry in re.findall(r'"((?:[^\\]|\\.)*?)"', line): 4119*cfb92d14SAndroid Build Coastguard Worker if '=' not in entry: 4120*cfb92d14SAndroid Build Coastguard Worker continue 4121*cfb92d14SAndroid Build Coastguard Worker 4122*cfb92d14SAndroid Build Coastguard Worker k, v = entry.split('=', 1) 4123*cfb92d14SAndroid Build Coastguard Worker txt[k] = v 4124*cfb92d14SAndroid Build Coastguard Worker 4125*cfb92d14SAndroid Build Coastguard Worker return txt 4126*cfb92d14SAndroid Build Coastguard Worker 4127*cfb92d14SAndroid Build Coastguard Worker 4128*cfb92d14SAndroid Build Coastguard Workerclass OtbrNode(LinuxHost, NodeImpl, OtbrDocker): 4129*cfb92d14SAndroid Build Coastguard Worker TUN_DEV = config.THREAD_IFNAME 4130*cfb92d14SAndroid Build Coastguard Worker is_otbr = True 4131*cfb92d14SAndroid Build Coastguard Worker is_bbr = True # OTBR is also BBR 4132*cfb92d14SAndroid Build Coastguard Worker node_type = 'otbr-docker' 4133*cfb92d14SAndroid Build Coastguard Worker 4134*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 4135*cfb92d14SAndroid Build Coastguard Worker return f'Otbr<{self.nodeid}>' 4136*cfb92d14SAndroid Build Coastguard Worker 4137*cfb92d14SAndroid Build Coastguard Worker def start(self): 4138*cfb92d14SAndroid Build Coastguard Worker self._setup_sysctl() 4139*cfb92d14SAndroid Build Coastguard Worker self.set_log_level(5) 4140*cfb92d14SAndroid Build Coastguard Worker super().start() 4141*cfb92d14SAndroid Build Coastguard Worker 4142*cfb92d14SAndroid Build Coastguard Worker def add_ipaddr(self, addr): 4143*cfb92d14SAndroid Build Coastguard Worker cmd = f'ip -6 addr add {addr}/64 dev {self.TUN_DEV}' 4144*cfb92d14SAndroid Build Coastguard Worker self.bash(cmd) 4145*cfb92d14SAndroid Build Coastguard Worker 4146*cfb92d14SAndroid Build Coastguard Worker def add_ipmaddr_tun(self, ip: str): 4147*cfb92d14SAndroid Build Coastguard Worker cmd = f'python3 /app/third_party/openthread/repo/tests/scripts/thread-cert/mcast6.py {self.TUN_DEV} {ip} &' 4148*cfb92d14SAndroid Build Coastguard Worker self.bash(cmd) 4149*cfb92d14SAndroid Build Coastguard Worker 4150*cfb92d14SAndroid Build Coastguard Worker def get_ip6_address(self, address_type: config.ADDRESS_TYPE): 4151*cfb92d14SAndroid Build Coastguard Worker try: 4152*cfb92d14SAndroid Build Coastguard Worker return super(OtbrNode, self).get_ip6_address(address_type) 4153*cfb92d14SAndroid Build Coastguard Worker except Exception as e: 4154*cfb92d14SAndroid Build Coastguard Worker return super(LinuxHost, self).get_ip6_address(address_type) 4155*cfb92d14SAndroid Build Coastguard Worker 4156*cfb92d14SAndroid Build Coastguard Worker 4157*cfb92d14SAndroid Build Coastguard Workerclass HostNode(LinuxHost, OtbrDocker): 4158*cfb92d14SAndroid Build Coastguard Worker is_host = True 4159*cfb92d14SAndroid Build Coastguard Worker 4160*cfb92d14SAndroid Build Coastguard Worker def __init__(self, nodeid, name=None, **kwargs): 4161*cfb92d14SAndroid Build Coastguard Worker self.nodeid = nodeid 4162*cfb92d14SAndroid Build Coastguard Worker self.name = name or ('Host%d' % nodeid) 4163*cfb92d14SAndroid Build Coastguard Worker super().__init__(nodeid, **kwargs) 4164*cfb92d14SAndroid Build Coastguard Worker self.bash('service otbr-agent stop') 4165*cfb92d14SAndroid Build Coastguard Worker 4166*cfb92d14SAndroid Build Coastguard Worker def start(self, start_radvd=True, prefix=config.DOMAIN_PREFIX, slaac=False): 4167*cfb92d14SAndroid Build Coastguard Worker self._setup_sysctl() 4168*cfb92d14SAndroid Build Coastguard Worker if start_radvd: 4169*cfb92d14SAndroid Build Coastguard Worker self.start_radvd_service(prefix, slaac) 4170*cfb92d14SAndroid Build Coastguard Worker else: 4171*cfb92d14SAndroid Build Coastguard Worker self.stop_radvd_service() 4172*cfb92d14SAndroid Build Coastguard Worker 4173*cfb92d14SAndroid Build Coastguard Worker def stop(self): 4174*cfb92d14SAndroid Build Coastguard Worker self.stop_radvd_service() 4175*cfb92d14SAndroid Build Coastguard Worker 4176*cfb92d14SAndroid Build Coastguard Worker def get_addrs(self) -> List[str]: 4177*cfb92d14SAndroid Build Coastguard Worker return self.get_ether_addrs() 4178*cfb92d14SAndroid Build Coastguard Worker 4179*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 4180*cfb92d14SAndroid Build Coastguard Worker return f'Host<{self.nodeid}>' 4181*cfb92d14SAndroid Build Coastguard Worker 4182*cfb92d14SAndroid Build Coastguard Worker def get_matched_ula_addresses(self, prefix): 4183*cfb92d14SAndroid Build Coastguard Worker """Get the IPv6 addresses that matches given prefix. 4184*cfb92d14SAndroid Build Coastguard Worker """ 4185*cfb92d14SAndroid Build Coastguard Worker 4186*cfb92d14SAndroid Build Coastguard Worker addrs = [] 4187*cfb92d14SAndroid Build Coastguard Worker for addr in self.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA): 4188*cfb92d14SAndroid Build Coastguard Worker if IPv6Address(addr) in IPv6Network(prefix): 4189*cfb92d14SAndroid Build Coastguard Worker addrs.append(addr) 4190*cfb92d14SAndroid Build Coastguard Worker 4191*cfb92d14SAndroid Build Coastguard Worker return addrs 4192*cfb92d14SAndroid Build Coastguard Worker 4193*cfb92d14SAndroid Build Coastguard Worker 4194*cfb92d14SAndroid Build Coastguard Workerif __name__ == '__main__': 4195*cfb92d14SAndroid Build Coastguard Worker unittest.main() 4196