mirror of
https://github.com/espressif/openthread.git
synced 2026-07-09 13:50:28 +00:00
71e00eb20f
This commits updates `thread-cert/Makefile.am` adding some existing tests that were not included in the Makefile when the tests were added. It also sorts the entries to be in alphabetical order. This commit also updates the access control mode for all script files to be executable by all (`chmod 755` or "-rwxr-xr-x").
331 lines
8.7 KiB
Python
Executable File
331 lines
8.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2020, The OpenThread Authors.
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
# 3. Neither the name of the copyright holder nor the
|
|
# names of its contributors may be used to endorse or promote products
|
|
# derived from this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
|
|
import struct
|
|
|
|
from enum import IntEnum
|
|
from typing import List
|
|
|
|
import common
|
|
import ipaddress
|
|
import mle
|
|
|
|
|
|
class TlvType(IntEnum):
|
|
EXT_ADDRESS = 0
|
|
ADDRESS16 = 1
|
|
MODE = 2
|
|
POLLING_PERIOD = 3
|
|
CONNECTIVITY = 4
|
|
ROUTE64 = 5
|
|
LEADER_DATA = 6
|
|
NETWORK_DATA = 7
|
|
IPV6_ADDRESS_LIST = 8
|
|
MAC_COUNTERS = 9
|
|
BATTERY_LEVEL = 14
|
|
SUPPLY_VOLTAGE = 15
|
|
CHILD_TABLE = 16
|
|
CHANNEL_PAGES = 17
|
|
TYPE_LIST = 18
|
|
MAX_CHILD_TIMEOUT = 19
|
|
|
|
|
|
class Ipv6AddressList:
|
|
|
|
def __init__(self, addresses: List[ipaddress.IPv6Address]):
|
|
self._addresses = addresses
|
|
|
|
@property
|
|
def addresses(self):
|
|
return self._addresses
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
return self.addresses == other.addresses
|
|
|
|
def __repr__(self):
|
|
return f'Ipv6AddressList({self.addresses})'
|
|
|
|
|
|
class Ipv6AddressListFactory:
|
|
|
|
def parse(self, data, message_info):
|
|
addresses = []
|
|
while data.tell() < message_info.length:
|
|
addresses.append(ipaddress.IPv6Address(data.read(16)))
|
|
return Ipv6AddressList(addresses)
|
|
|
|
|
|
class MacCounters:
|
|
|
|
def __init__(self, counters: List[int]):
|
|
self._counters = counters
|
|
|
|
@property
|
|
def if_in_unknown_protos(self):
|
|
return self._counters[0]
|
|
|
|
@property
|
|
def if_in_errors(self):
|
|
return self._counters[1]
|
|
|
|
@property
|
|
def if_out_errors(self):
|
|
return self._counters[2]
|
|
|
|
@property
|
|
def if_in_ucast_pkts(self):
|
|
return self._counters[3]
|
|
|
|
@property
|
|
def if_in_broadcast_pkts(self):
|
|
return self._counters[4]
|
|
|
|
@property
|
|
def if_in_discards(self):
|
|
return self._counters[5]
|
|
|
|
@property
|
|
def if_out_ucast_pkts(self):
|
|
return self._counters[6]
|
|
|
|
@property
|
|
def if_out_broadcast_pkts(self):
|
|
return self._counters[7]
|
|
|
|
@property
|
|
def if_out_discards(self):
|
|
return self._counters[8]
|
|
|
|
@property
|
|
def counters(self):
|
|
return self._counters
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
|
|
return self.counters == other.counters
|
|
|
|
def __repr__(self):
|
|
return ('MacCounters(' + f'if_in_unknown_protos={self.if_in_unknown_protos}, ' +
|
|
f'if_in_errors={self.if_in_errors}, ' + f'if_out_errors={self.if_out_errors}, ' +
|
|
f'if_in_ucast_pkts={self.if_in_ucast_pkts}, ' + f'if_in_broadcast_pkts={self.if_in_broadcast_pkts}, ' +
|
|
f'if_in_discards={self.if_in_discards}, ' + f'if_out_ucast_pkts={self.if_out_ucast_pkts}, ' +
|
|
f'if_out_broadcast_pkts={self.if_out_broadcast_pkts}, ' + f'if_out_discards={self.if_out_discards})')
|
|
|
|
|
|
class MacCountersFactory:
|
|
|
|
def parse(self, data, message_info):
|
|
return MacCounters(struct.unpack('>9I', data.read(4 * 9)))
|
|
|
|
|
|
class BatteryLevel:
|
|
|
|
def __init__(self, battery_level: int):
|
|
self._battery_level = battery_level
|
|
|
|
@property
|
|
def battery_level(self):
|
|
return self._battery_level
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
|
|
return self.battery_level == other.battery_level
|
|
|
|
def __repr__(self):
|
|
return f'BatteryLevel(battery_level={self.battery_level})'
|
|
|
|
|
|
class BatteryLevelFactory:
|
|
|
|
def parse(self, data, message_info):
|
|
return BatteryLevel(struct.unpack('>B', data.read(1))[0])
|
|
|
|
|
|
class SupplyVoltage:
|
|
|
|
def __init__(self, supply_voltage: int):
|
|
self._supply_voltage = supply_voltage
|
|
|
|
@property
|
|
def supply_voltage(self):
|
|
return self._supply_voltage
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
|
|
return self.supply_voltage == other.supply_voltage
|
|
|
|
def __repr__(self):
|
|
return f'SupplyVoltage(supply_voltage={self.supply_voltage})'
|
|
|
|
|
|
class SupplyVoltageFactory:
|
|
|
|
def parse(self, data, message_info):
|
|
return SupplyVoltage(struct.unpack('>H', data.read(2))[0])
|
|
|
|
|
|
class ChildTableEntry:
|
|
|
|
def __init__(self, timeout: int, child_id: int, mode: mle.Mode):
|
|
self._timeout = timeout
|
|
self._child_id = child_id
|
|
self._mode = mode
|
|
|
|
@property
|
|
def timeout(self):
|
|
return self._timeout
|
|
|
|
@property
|
|
def child_id(self):
|
|
return self._child_id
|
|
|
|
@property
|
|
def mode(self):
|
|
return self._mode
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
|
|
return (self.timeout == other.timeout and self.child_id == other.child_id and self.mode == other.mode)
|
|
|
|
def __repr__(self):
|
|
return f'ChildTableEntry(timeout={self.timeout}, child_id={self.child_id}, mode={self.mode})'
|
|
|
|
|
|
class ChildTable:
|
|
|
|
def __init__(self, children: List[ChildTableEntry]):
|
|
self._children = sorted(children, key=lambda child: child.child_id)
|
|
|
|
@property
|
|
def children(self):
|
|
return self._children
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
|
|
return self.children == other.children
|
|
|
|
def __repr__(self):
|
|
return f'ChildTable({self.children})'
|
|
|
|
|
|
class ChildTableFactory:
|
|
|
|
def parse(self, data, message_info):
|
|
children = []
|
|
while message_info.length > 0:
|
|
timeout_and_id = struct.unpack('>H', data.read(2))[0]
|
|
message_info.length -= 2
|
|
|
|
timeout = (timeout_and_id & 0xf800) >> 11
|
|
child_id = timeout_and_id & 0x1fff
|
|
|
|
mode = mle.ModeFactory().parse(data, message_info)
|
|
message_info.length -= 1
|
|
|
|
children.append(ChildTableEntry(timeout, child_id, mode))
|
|
return ChildTable(children)
|
|
|
|
|
|
class ChannelPages:
|
|
|
|
def __init__(self, channel_pages: bytes):
|
|
self._channel_pages = channel_pages
|
|
|
|
@property
|
|
def channel_pages(self):
|
|
return self._channel_pages
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
|
|
return self.channel_pages == other.channel_pages
|
|
|
|
def __repr__(self):
|
|
return f'ChannelPages(channel_pages={self.channel_pages})'
|
|
|
|
|
|
class ChannelPagesFactory:
|
|
|
|
def parse(self, data, message_info):
|
|
return ChannelPages(data.getvalue())
|
|
|
|
|
|
class TypeList:
|
|
|
|
def __init__(self, tlv_types: List[int]):
|
|
self._tlv_types = tlv_types
|
|
|
|
@property
|
|
def tlv_types(self):
|
|
return self._tlv_types
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
|
|
return self.tlv_types == other.tlv_types
|
|
|
|
def __repr__(self):
|
|
return f'TypeList(tlv_types={self.tlv_types})'
|
|
|
|
|
|
class TypeListFactory:
|
|
|
|
def parse(self, data, message_info):
|
|
return TypeList([ord(t) for t in data.getvalue()])
|
|
|
|
|
|
class MaxChildTimeout:
|
|
|
|
def __init__(self, max_child_timeout: int):
|
|
self._max_child_timeout = max_child_timeout
|
|
|
|
@property
|
|
def max_child_timeout(self):
|
|
return self._max_child_timeout
|
|
|
|
def __eq__(self, other):
|
|
common.expect_the_same_class(self, other)
|
|
|
|
return self.max_child_timeout == other.max_child_timeout
|
|
|
|
def __repr__(self):
|
|
return f'MaxChildTimeout(max_child_timeout={self.max_child_timeout})'
|
|
|
|
|
|
class MaxChildTimeoutFactory:
|
|
|
|
def parse(self, data, message_info):
|
|
return MaxChildTimeout(struct.unpack('>I', data.read(4))[0])
|