mirror of
https://github.com/espressif/openthread.git
synced 2026-08-21 01:49:52 +00:00
[tests] support testing commissioning (#3441)
Add support for testing commissioning process, including: 1. Add DTLS, Thread Discovery and commissioning messages(JOIN_FIN.req etc) parsing; 2. Support parsing log from UART response, and construct decrypted messages; 3. Common commands for commissioning related verification;
This commit is contained in:
@@ -34,6 +34,7 @@ import sys
|
||||
|
||||
import coap
|
||||
import common
|
||||
import dtls
|
||||
import ipv6
|
||||
import lowpan
|
||||
import mac802154
|
||||
@@ -49,6 +50,7 @@ class MessageType(IntEnum):
|
||||
BEACON = 4
|
||||
DATA = 5
|
||||
COMMAND = 6
|
||||
DTLS = 7
|
||||
|
||||
|
||||
class Message(object):
|
||||
@@ -61,6 +63,7 @@ class Message(object):
|
||||
self._coap = None
|
||||
self._mle = None
|
||||
self._icmp = None
|
||||
self._dtls = None
|
||||
|
||||
def _extract_udp_datagram(self, udp_datagram):
|
||||
if isinstance(udp_datagram.payload, mle.MleMessage):
|
||||
@@ -71,6 +74,11 @@ class Message(object):
|
||||
self._type = MessageType.COAP
|
||||
self._coap = udp_datagram.payload
|
||||
|
||||
# DTLS message factory returns a list of messages
|
||||
elif isinstance(udp_datagram.payload, list):
|
||||
self._type = MessageType.DTLS
|
||||
self._dtls = udp_datagram.payload
|
||||
|
||||
def _extract_upper_layer_protocol(self, upper_layer_protocol):
|
||||
if isinstance(upper_layer_protocol, ipv6.ICMPv6):
|
||||
self._type = MessageType.ICMP
|
||||
@@ -79,6 +87,32 @@ class Message(object):
|
||||
elif isinstance(upper_layer_protocol, ipv6.UDPDatagram):
|
||||
self._extract_udp_datagram(upper_layer_protocol)
|
||||
|
||||
def try_extract_dtls_messages(self):
|
||||
"""Extract multiple dtls messages that are sent in a single UDP datagram
|
||||
"""
|
||||
if self.type != MessageType.DTLS:
|
||||
return [self.clone()]
|
||||
|
||||
assert isinstance(self.dtls, list)
|
||||
ret = []
|
||||
for dtls in self.dtls:
|
||||
msg = self.clone()
|
||||
msg._dtls = dtls
|
||||
ret.append(msg)
|
||||
return ret
|
||||
|
||||
def clone(self):
|
||||
msg = Message()
|
||||
msg._type = self.type
|
||||
msg._channel = self.channel
|
||||
msg._mac_header = self.mac_header
|
||||
msg._ipv6_packet = self.ipv6_packet
|
||||
msg._coap = self.coap
|
||||
msg._mle = self.mle
|
||||
msg._icmp = self.icmp
|
||||
msg._dtls = self.dtls
|
||||
return msg
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
@@ -141,6 +175,10 @@ class Message(object):
|
||||
def icmp(self, value):
|
||||
self._icmp = value
|
||||
|
||||
@property
|
||||
def dtls(self):
|
||||
return self._dtls
|
||||
|
||||
def get_mle_message_tlv(self, tlv_class_type):
|
||||
if self.type != MessageType.MLE:
|
||||
raise ValueError("Invalid message type. Expected MLE message.")
|
||||
@@ -306,19 +344,30 @@ class Message(object):
|
||||
def isMacAddressTypeLong(self):
|
||||
return self.mac_header.dest_address.type == common.MacAddressType.LONG
|
||||
|
||||
def get_dst_udp_port(self):
|
||||
assert isinstance(self.ipv6_packet.upper_layer_protocol, ipv6.UDPDatagram)
|
||||
return self.ipv6_packet.upper_layer_protocol.header.dst_port
|
||||
|
||||
def __repr__(self):
|
||||
if self.type == MessageType.DTLS and self.dtls.content_type == dtls.ContentType.HANDSHAKE:
|
||||
return "Message(type={})".format(str(self.dtls.handshake_type))
|
||||
return "Message(type={})".format(MessageType(self.type).name)
|
||||
|
||||
|
||||
class MessagesSet(object):
|
||||
|
||||
def __init__(self, messages):
|
||||
def __init__(self, messages, commissioning_messages=[]):
|
||||
self._messages = messages
|
||||
self._commissioning_messages = commissioning_messages
|
||||
|
||||
@property
|
||||
def messages(self):
|
||||
return self._messages
|
||||
|
||||
@property
|
||||
def commissioning_messages(self):
|
||||
return self._commissioning_messages
|
||||
|
||||
def next_coap_message(self, code, uri_path=None, assert_enabled=True):
|
||||
message = None
|
||||
|
||||
@@ -433,6 +482,21 @@ class MessagesSet(object):
|
||||
def next_command_message(self):
|
||||
return self.next_message_of(MessageType.COMMAND)
|
||||
|
||||
def next_dtls_message(self, content_type, handshake_type=None):
|
||||
while self.messages:
|
||||
msg = self.messages.pop(0)
|
||||
if msg.type != MessageType.DTLS:
|
||||
continue
|
||||
if msg.dtls.content_type != content_type:
|
||||
continue
|
||||
if (content_type == dtls.ContentType.HANDSHAKE and
|
||||
msg.dtls.handshake_type != handshake_type):
|
||||
continue
|
||||
return msg
|
||||
|
||||
t = handshake_type if content_type == dtls.ContentType.HANDSHAKE else content_type
|
||||
raise ValueError("Could not find DTLS message of type: {}".format(str(t)))
|
||||
|
||||
def contains_icmp_message(self):
|
||||
for m in self.messages:
|
||||
if m.type == MessageType.ICMP:
|
||||
@@ -472,7 +536,10 @@ class MessagesSet(object):
|
||||
def clone(self):
|
||||
"""Make a copy of current MessageSet.
|
||||
"""
|
||||
return MessagesSet(self.messages[:])
|
||||
return MessagesSet(self.messages[:], self.commissioning_messages[:])
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.messages)
|
||||
|
||||
|
||||
class MessageFactory:
|
||||
@@ -506,7 +573,7 @@ class MessageFactory:
|
||||
message.mac_header = mac_frame.header
|
||||
|
||||
if message.mac_header.frame_type != mac802154.MacHeader.FrameType.DATA:
|
||||
return message
|
||||
return [message]
|
||||
|
||||
message_info = common.MessageInfo()
|
||||
message_info.source_mac_address = message.mac_header.src_address
|
||||
@@ -517,11 +584,11 @@ class MessageFactory:
|
||||
|
||||
ipv6_packet = self._lowpan_parser.parse(lowpan_payload, message_info)
|
||||
if ipv6_packet is None:
|
||||
return message
|
||||
return [message]
|
||||
|
||||
message.ipv6_packet = ipv6_packet
|
||||
|
||||
if message.type == MessageType.MLE:
|
||||
self._add_device_descriptors(message)
|
||||
|
||||
return message
|
||||
return message.try_extract_dtls_messages()
|
||||
|
||||
Reference in New Issue
Block a user