xref: /aosp_15_r20/external/openthread/tests/scripts/thread-cert/message.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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 io
31*cfb92d14SAndroid Build Coastguard Workerimport ipaddress
32*cfb92d14SAndroid Build Coastguard Workerimport struct
33*cfb92d14SAndroid Build Coastguard Worker
34*cfb92d14SAndroid Build Coastguard Workerimport coap
35*cfb92d14SAndroid Build Coastguard Workerimport common
36*cfb92d14SAndroid Build Coastguard Workerimport dtls
37*cfb92d14SAndroid Build Coastguard Workerimport ipv6
38*cfb92d14SAndroid Build Coastguard Workerimport mac802154
39*cfb92d14SAndroid Build Coastguard Workerimport mle
40*cfb92d14SAndroid Build Coastguard Worker
41*cfb92d14SAndroid Build Coastguard Workerfrom enum import IntEnum
42*cfb92d14SAndroid Build Coastguard Worker
43*cfb92d14SAndroid Build Coastguard Worker
44*cfb92d14SAndroid Build Coastguard Workerclass DropPacketException(Exception):
45*cfb92d14SAndroid Build Coastguard Worker    pass
46*cfb92d14SAndroid Build Coastguard Worker
47*cfb92d14SAndroid Build Coastguard Worker
48*cfb92d14SAndroid Build Coastguard Workerclass MessageType(IntEnum):
49*cfb92d14SAndroid Build Coastguard Worker    MLE = 0
50*cfb92d14SAndroid Build Coastguard Worker    COAP = 1
51*cfb92d14SAndroid Build Coastguard Worker    ICMP = 2
52*cfb92d14SAndroid Build Coastguard Worker    ACK = 3
53*cfb92d14SAndroid Build Coastguard Worker    BEACON = 4
54*cfb92d14SAndroid Build Coastguard Worker    DATA = 5
55*cfb92d14SAndroid Build Coastguard Worker    COMMAND = 6
56*cfb92d14SAndroid Build Coastguard Worker    DTLS = 7
57*cfb92d14SAndroid Build Coastguard Worker
58*cfb92d14SAndroid Build Coastguard Worker
59*cfb92d14SAndroid Build Coastguard Workerclass Message(object):
60*cfb92d14SAndroid Build Coastguard Worker
61*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
62*cfb92d14SAndroid Build Coastguard Worker        self._type = None
63*cfb92d14SAndroid Build Coastguard Worker        self._channel = None
64*cfb92d14SAndroid Build Coastguard Worker        self._mac_header = None
65*cfb92d14SAndroid Build Coastguard Worker        self._ipv6_packet = None
66*cfb92d14SAndroid Build Coastguard Worker        self._coap = None
67*cfb92d14SAndroid Build Coastguard Worker        self._mle = None
68*cfb92d14SAndroid Build Coastguard Worker        self._icmp = None
69*cfb92d14SAndroid Build Coastguard Worker        self._dtls = None
70*cfb92d14SAndroid Build Coastguard Worker
71*cfb92d14SAndroid Build Coastguard Worker    def _extract_udp_datagram(self, udp_datagram):
72*cfb92d14SAndroid Build Coastguard Worker        if isinstance(udp_datagram.payload, mle.MleMessage):
73*cfb92d14SAndroid Build Coastguard Worker            self._type = MessageType.MLE
74*cfb92d14SAndroid Build Coastguard Worker            self._mle = udp_datagram.payload
75*cfb92d14SAndroid Build Coastguard Worker
76*cfb92d14SAndroid Build Coastguard Worker        elif isinstance(udp_datagram.payload, (coap.CoapMessage, coap.CoapMessageProxy)):
77*cfb92d14SAndroid Build Coastguard Worker            self._type = MessageType.COAP
78*cfb92d14SAndroid Build Coastguard Worker            self._coap = udp_datagram.payload
79*cfb92d14SAndroid Build Coastguard Worker
80*cfb92d14SAndroid Build Coastguard Worker        # DTLS message factory returns a list of messages
81*cfb92d14SAndroid Build Coastguard Worker        elif isinstance(udp_datagram.payload, list):
82*cfb92d14SAndroid Build Coastguard Worker            self._type = MessageType.DTLS
83*cfb92d14SAndroid Build Coastguard Worker            self._dtls = udp_datagram.payload
84*cfb92d14SAndroid Build Coastguard Worker
85*cfb92d14SAndroid Build Coastguard Worker    def _extract_upper_layer_protocol(self, upper_layer_protocol):
86*cfb92d14SAndroid Build Coastguard Worker        if isinstance(upper_layer_protocol, ipv6.ICMPv6):
87*cfb92d14SAndroid Build Coastguard Worker            self._type = MessageType.ICMP
88*cfb92d14SAndroid Build Coastguard Worker            self._icmp = upper_layer_protocol
89*cfb92d14SAndroid Build Coastguard Worker
90*cfb92d14SAndroid Build Coastguard Worker        elif isinstance(upper_layer_protocol, ipv6.UDPDatagram):
91*cfb92d14SAndroid Build Coastguard Worker            self._extract_udp_datagram(upper_layer_protocol)
92*cfb92d14SAndroid Build Coastguard Worker
93*cfb92d14SAndroid Build Coastguard Worker    def try_extract_dtls_messages(self):
94*cfb92d14SAndroid Build Coastguard Worker        """Extract multiple dtls messages that are sent in a single UDP datagram
95*cfb92d14SAndroid Build Coastguard Worker        """
96*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.DTLS:
97*cfb92d14SAndroid Build Coastguard Worker            return [self.clone()]
98*cfb92d14SAndroid Build Coastguard Worker
99*cfb92d14SAndroid Build Coastguard Worker        assert isinstance(self.dtls, list)
100*cfb92d14SAndroid Build Coastguard Worker        ret = []
101*cfb92d14SAndroid Build Coastguard Worker        for dtls in self.dtls:
102*cfb92d14SAndroid Build Coastguard Worker            msg = self.clone()
103*cfb92d14SAndroid Build Coastguard Worker            msg._dtls = dtls
104*cfb92d14SAndroid Build Coastguard Worker            ret.append(msg)
105*cfb92d14SAndroid Build Coastguard Worker        return ret
106*cfb92d14SAndroid Build Coastguard Worker
107*cfb92d14SAndroid Build Coastguard Worker    def clone(self):
108*cfb92d14SAndroid Build Coastguard Worker        msg = Message()
109*cfb92d14SAndroid Build Coastguard Worker        msg._type = self.type
110*cfb92d14SAndroid Build Coastguard Worker        msg._channel = self.channel
111*cfb92d14SAndroid Build Coastguard Worker        msg._mac_header = self.mac_header
112*cfb92d14SAndroid Build Coastguard Worker        msg._ipv6_packet = self.ipv6_packet
113*cfb92d14SAndroid Build Coastguard Worker        msg._coap = self.coap
114*cfb92d14SAndroid Build Coastguard Worker        msg._mle = self.mle
115*cfb92d14SAndroid Build Coastguard Worker        msg._icmp = self.icmp
116*cfb92d14SAndroid Build Coastguard Worker        msg._dtls = self.dtls
117*cfb92d14SAndroid Build Coastguard Worker        return msg
118*cfb92d14SAndroid Build Coastguard Worker
119*cfb92d14SAndroid Build Coastguard Worker    @property
120*cfb92d14SAndroid Build Coastguard Worker    def type(self):
121*cfb92d14SAndroid Build Coastguard Worker        return self._type
122*cfb92d14SAndroid Build Coastguard Worker
123*cfb92d14SAndroid Build Coastguard Worker    @type.setter
124*cfb92d14SAndroid Build Coastguard Worker    def type(self, value):
125*cfb92d14SAndroid Build Coastguard Worker        self._type = value
126*cfb92d14SAndroid Build Coastguard Worker
127*cfb92d14SAndroid Build Coastguard Worker    @property
128*cfb92d14SAndroid Build Coastguard Worker    def channel(self):
129*cfb92d14SAndroid Build Coastguard Worker        return self._channel
130*cfb92d14SAndroid Build Coastguard Worker
131*cfb92d14SAndroid Build Coastguard Worker    @channel.setter
132*cfb92d14SAndroid Build Coastguard Worker    def channel(self, value):
133*cfb92d14SAndroid Build Coastguard Worker        self._channel = value
134*cfb92d14SAndroid Build Coastguard Worker
135*cfb92d14SAndroid Build Coastguard Worker    @property
136*cfb92d14SAndroid Build Coastguard Worker    def mac_header(self):
137*cfb92d14SAndroid Build Coastguard Worker        return self._mac_header
138*cfb92d14SAndroid Build Coastguard Worker
139*cfb92d14SAndroid Build Coastguard Worker    @mac_header.setter
140*cfb92d14SAndroid Build Coastguard Worker    def mac_header(self, value):
141*cfb92d14SAndroid Build Coastguard Worker        self._mac_header = value
142*cfb92d14SAndroid Build Coastguard Worker
143*cfb92d14SAndroid Build Coastguard Worker        if self._mac_header.frame_type == mac802154.MacHeader.FrameType.BEACON:
144*cfb92d14SAndroid Build Coastguard Worker            self._type = MessageType.BEACON
145*cfb92d14SAndroid Build Coastguard Worker
146*cfb92d14SAndroid Build Coastguard Worker        elif self._mac_header.frame_type == mac802154.MacHeader.FrameType.ACK:
147*cfb92d14SAndroid Build Coastguard Worker            self._type = MessageType.ACK
148*cfb92d14SAndroid Build Coastguard Worker
149*cfb92d14SAndroid Build Coastguard Worker        elif self._mac_header.frame_type == mac802154.MacHeader.FrameType.DATA:
150*cfb92d14SAndroid Build Coastguard Worker            self._type = MessageType.DATA
151*cfb92d14SAndroid Build Coastguard Worker        elif (self._mac_header.frame_type == mac802154.MacHeader.FrameType.COMMAND):
152*cfb92d14SAndroid Build Coastguard Worker            self._type = MessageType.COMMAND
153*cfb92d14SAndroid Build Coastguard Worker        else:
154*cfb92d14SAndroid Build Coastguard Worker            raise ValueError('Invalid mac frame type %d' % self._mac_header.frame_type)
155*cfb92d14SAndroid Build Coastguard Worker
156*cfb92d14SAndroid Build Coastguard Worker    @property
157*cfb92d14SAndroid Build Coastguard Worker    def ipv6_packet(self):
158*cfb92d14SAndroid Build Coastguard Worker        return self._ipv6_packet
159*cfb92d14SAndroid Build Coastguard Worker
160*cfb92d14SAndroid Build Coastguard Worker    @ipv6_packet.setter
161*cfb92d14SAndroid Build Coastguard Worker    def ipv6_packet(self, value):
162*cfb92d14SAndroid Build Coastguard Worker        self._ipv6_packet = value
163*cfb92d14SAndroid Build Coastguard Worker        self._extract_upper_layer_protocol(value.upper_layer_protocol)
164*cfb92d14SAndroid Build Coastguard Worker
165*cfb92d14SAndroid Build Coastguard Worker    @property
166*cfb92d14SAndroid Build Coastguard Worker    def coap(self):
167*cfb92d14SAndroid Build Coastguard Worker        return self._coap
168*cfb92d14SAndroid Build Coastguard Worker
169*cfb92d14SAndroid Build Coastguard Worker    @property
170*cfb92d14SAndroid Build Coastguard Worker    def mle(self):
171*cfb92d14SAndroid Build Coastguard Worker        return self._mle
172*cfb92d14SAndroid Build Coastguard Worker
173*cfb92d14SAndroid Build Coastguard Worker    @property
174*cfb92d14SAndroid Build Coastguard Worker    def icmp(self):
175*cfb92d14SAndroid Build Coastguard Worker        return self._icmp
176*cfb92d14SAndroid Build Coastguard Worker
177*cfb92d14SAndroid Build Coastguard Worker    @icmp.setter
178*cfb92d14SAndroid Build Coastguard Worker    def icmp(self, value):
179*cfb92d14SAndroid Build Coastguard Worker        self._icmp = value
180*cfb92d14SAndroid Build Coastguard Worker
181*cfb92d14SAndroid Build Coastguard Worker    @property
182*cfb92d14SAndroid Build Coastguard Worker    def dtls(self):
183*cfb92d14SAndroid Build Coastguard Worker        return self._dtls
184*cfb92d14SAndroid Build Coastguard Worker
185*cfb92d14SAndroid Build Coastguard Worker    def get_mle_message_tlv(self, tlv_class_type):
186*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.MLE:
187*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected MLE message.")
188*cfb92d14SAndroid Build Coastguard Worker
189*cfb92d14SAndroid Build Coastguard Worker        for tlv in self.mle.command.tlvs:
190*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, tlv_class_type):
191*cfb92d14SAndroid Build Coastguard Worker                return tlv
192*cfb92d14SAndroid Build Coastguard Worker
193*cfb92d14SAndroid Build Coastguard Worker    def assertMleMessageIsType(self, command_type):
194*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.MLE:
195*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected MLE message.")
196*cfb92d14SAndroid Build Coastguard Worker
197*cfb92d14SAndroid Build Coastguard Worker        assert self.mle.command.type == command_type
198*cfb92d14SAndroid Build Coastguard Worker
199*cfb92d14SAndroid Build Coastguard Worker    def assertMleMessageContainsTlv(self, tlv_class_type):
200*cfb92d14SAndroid Build Coastguard Worker        """To confirm if Mle message contains the TLV type.
201*cfb92d14SAndroid Build Coastguard Worker
202*cfb92d14SAndroid Build Coastguard Worker        Args:
203*cfb92d14SAndroid Build Coastguard Worker            tlv_class_type: tlv's type.
204*cfb92d14SAndroid Build Coastguard Worker
205*cfb92d14SAndroid Build Coastguard Worker        Returns:
206*cfb92d14SAndroid Build Coastguard Worker            mle.Route64: If contains the TLV, return it.
207*cfb92d14SAndroid Build Coastguard Worker        """
208*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.MLE:
209*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected MLE message.")
210*cfb92d14SAndroid Build Coastguard Worker
211*cfb92d14SAndroid Build Coastguard Worker        contains_tlv = False
212*cfb92d14SAndroid Build Coastguard Worker        for tlv in self.mle.command.tlvs:
213*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, tlv_class_type):
214*cfb92d14SAndroid Build Coastguard Worker                contains_tlv = True
215*cfb92d14SAndroid Build Coastguard Worker                break
216*cfb92d14SAndroid Build Coastguard Worker
217*cfb92d14SAndroid Build Coastguard Worker        assert contains_tlv
218*cfb92d14SAndroid Build Coastguard Worker        return tlv
219*cfb92d14SAndroid Build Coastguard Worker
220*cfb92d14SAndroid Build Coastguard Worker    def assertAssignedRouterQuantity(self, router_quantity):
221*cfb92d14SAndroid Build Coastguard Worker        """Confirm if Leader contains the Route64 TLV with router_quantity assigned Router IDs.
222*cfb92d14SAndroid Build Coastguard Worker
223*cfb92d14SAndroid Build Coastguard Worker        Args:
224*cfb92d14SAndroid Build Coastguard Worker            router_quantity: the quantity of router.
225*cfb92d14SAndroid Build Coastguard Worker        """
226*cfb92d14SAndroid Build Coastguard Worker        tlv = self.assertMleMessageContainsTlv(mle.Route64)
227*cfb92d14SAndroid Build Coastguard Worker        router_id_mask = tlv.router_id_mask
228*cfb92d14SAndroid Build Coastguard Worker
229*cfb92d14SAndroid Build Coastguard Worker        count = 0
230*cfb92d14SAndroid Build Coastguard Worker        for i in range(1, 65):
231*cfb92d14SAndroid Build Coastguard Worker            count += router_id_mask & 1
232*cfb92d14SAndroid Build Coastguard Worker            router_id_mask = router_id_mask >> 1
233*cfb92d14SAndroid Build Coastguard Worker        assert count == router_quantity
234*cfb92d14SAndroid Build Coastguard Worker
235*cfb92d14SAndroid Build Coastguard Worker    def assertMleMessageDoesNotContainTlv(self, tlv_class_type):
236*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.MLE:
237*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected MLE message.")
238*cfb92d14SAndroid Build Coastguard Worker
239*cfb92d14SAndroid Build Coastguard Worker        contains_tlv = False
240*cfb92d14SAndroid Build Coastguard Worker        for tlv in self.mle.command.tlvs:
241*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, tlv_class_type):
242*cfb92d14SAndroid Build Coastguard Worker                contains_tlv = True
243*cfb92d14SAndroid Build Coastguard Worker                break
244*cfb92d14SAndroid Build Coastguard Worker
245*cfb92d14SAndroid Build Coastguard Worker        assert contains_tlv is False
246*cfb92d14SAndroid Build Coastguard Worker
247*cfb92d14SAndroid Build Coastguard Worker    def assertMleMessageContainsOptionalTlv(self, tlv_class_type):
248*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.MLE:
249*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected MLE message.")
250*cfb92d14SAndroid Build Coastguard Worker
251*cfb92d14SAndroid Build Coastguard Worker        contains_tlv = False
252*cfb92d14SAndroid Build Coastguard Worker        for tlv in self.mle.command.tlvs:
253*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, tlv_class_type):
254*cfb92d14SAndroid Build Coastguard Worker                contains_tlv = True
255*cfb92d14SAndroid Build Coastguard Worker                break
256*cfb92d14SAndroid Build Coastguard Worker
257*cfb92d14SAndroid Build Coastguard Worker        if contains_tlv:
258*cfb92d14SAndroid Build Coastguard Worker            print("MleMessage contains optional TLV: {}".format(tlv_class_type))
259*cfb92d14SAndroid Build Coastguard Worker        else:
260*cfb92d14SAndroid Build Coastguard Worker            print("MleMessage doesn't contain optional TLV: {}".format(tlv_class_type))
261*cfb92d14SAndroid Build Coastguard Worker
262*cfb92d14SAndroid Build Coastguard Worker    def get_coap_message_tlv(self, tlv_class_type):
263*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.COAP:
264*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected CoAP message.")
265*cfb92d14SAndroid Build Coastguard Worker
266*cfb92d14SAndroid Build Coastguard Worker        for tlv in self.coap.payload:
267*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, tlv_class_type):
268*cfb92d14SAndroid Build Coastguard Worker                return tlv
269*cfb92d14SAndroid Build Coastguard Worker
270*cfb92d14SAndroid Build Coastguard Worker    def assertCoapMessageContainsTlv(self, tlv_class_type):
271*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.COAP:
272*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected CoAP message.")
273*cfb92d14SAndroid Build Coastguard Worker
274*cfb92d14SAndroid Build Coastguard Worker        contains_tlv = False
275*cfb92d14SAndroid Build Coastguard Worker        for tlv in self.coap.payload:
276*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, tlv_class_type):
277*cfb92d14SAndroid Build Coastguard Worker                contains_tlv = True
278*cfb92d14SAndroid Build Coastguard Worker                break
279*cfb92d14SAndroid Build Coastguard Worker
280*cfb92d14SAndroid Build Coastguard Worker        assert contains_tlv
281*cfb92d14SAndroid Build Coastguard Worker
282*cfb92d14SAndroid Build Coastguard Worker    def assertCoapMessageDoesNotContainTlv(self, tlv_class_type):
283*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.COAP:
284*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected COAP message.")
285*cfb92d14SAndroid Build Coastguard Worker
286*cfb92d14SAndroid Build Coastguard Worker        contains_tlv = False
287*cfb92d14SAndroid Build Coastguard Worker        for tlv in self.coap.payload:
288*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, tlv_class_type):
289*cfb92d14SAndroid Build Coastguard Worker                contains_tlv = True
290*cfb92d14SAndroid Build Coastguard Worker                break
291*cfb92d14SAndroid Build Coastguard Worker
292*cfb92d14SAndroid Build Coastguard Worker        assert contains_tlv is False
293*cfb92d14SAndroid Build Coastguard Worker
294*cfb92d14SAndroid Build Coastguard Worker    def assertCoapMessageContainsOptionalTlv(self, tlv_class_type):
295*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.COAP:
296*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected CoAP message.")
297*cfb92d14SAndroid Build Coastguard Worker
298*cfb92d14SAndroid Build Coastguard Worker        for tlv in self.coap.payload:
299*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, tlv_class_type):
300*cfb92d14SAndroid Build Coastguard Worker                break
301*cfb92d14SAndroid Build Coastguard Worker
302*cfb92d14SAndroid Build Coastguard Worker        print("CoapMessage doesn't contain optional TLV: {}".format(tlv_class_type))
303*cfb92d14SAndroid Build Coastguard Worker
304*cfb92d14SAndroid Build Coastguard Worker    def assertCoapMessageRequestUriPath(self, uri_path):
305*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.COAP:
306*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected CoAP message.")
307*cfb92d14SAndroid Build Coastguard Worker
308*cfb92d14SAndroid Build Coastguard Worker        assert uri_path == self.coap.uri_path
309*cfb92d14SAndroid Build Coastguard Worker
310*cfb92d14SAndroid Build Coastguard Worker    def assertCoapMessageCode(self, code):
311*cfb92d14SAndroid Build Coastguard Worker        if self.type != MessageType.COAP:
312*cfb92d14SAndroid Build Coastguard Worker            raise ValueError("Invalid message type. Expected CoAP message.")
313*cfb92d14SAndroid Build Coastguard Worker
314*cfb92d14SAndroid Build Coastguard Worker        assert code == self.coap.code
315*cfb92d14SAndroid Build Coastguard Worker
316*cfb92d14SAndroid Build Coastguard Worker    def assertSentToNode(self, node):
317*cfb92d14SAndroid Build Coastguard Worker        sent_to_node = False
318*cfb92d14SAndroid Build Coastguard Worker        dst_addr = self.ipv6_packet.ipv6_header.destination_address
319*cfb92d14SAndroid Build Coastguard Worker
320*cfb92d14SAndroid Build Coastguard Worker        for addr in node.get_addrs():
321*cfb92d14SAndroid Build Coastguard Worker            if dst_addr == ipaddress.ip_address(addr):
322*cfb92d14SAndroid Build Coastguard Worker                sent_to_node = True
323*cfb92d14SAndroid Build Coastguard Worker
324*cfb92d14SAndroid Build Coastguard Worker        if self.mac_header.dest_address.type == common.MacAddressType.SHORT:
325*cfb92d14SAndroid Build Coastguard Worker            mac_address = common.MacAddress.from_rloc16(node.get_addr16())
326*cfb92d14SAndroid Build Coastguard Worker            if self.mac_header.dest_address == mac_address:
327*cfb92d14SAndroid Build Coastguard Worker                sent_to_node = True
328*cfb92d14SAndroid Build Coastguard Worker
329*cfb92d14SAndroid Build Coastguard Worker        elif self.mac_header.dest_address.type == common.MacAddressType.LONG:
330*cfb92d14SAndroid Build Coastguard Worker            mac_address = common.MacAddress.from_eui64(bytearray(node.get_addr64(), encoding="utf-8"))
331*cfb92d14SAndroid Build Coastguard Worker            if self.mac_header.dest_address == mac_address:
332*cfb92d14SAndroid Build Coastguard Worker                sent_to_node = True
333*cfb92d14SAndroid Build Coastguard Worker
334*cfb92d14SAndroid Build Coastguard Worker        assert sent_to_node
335*cfb92d14SAndroid Build Coastguard Worker
336*cfb92d14SAndroid Build Coastguard Worker    def assertSentToDestinationAddress(self, ipv6_address):
337*cfb92d14SAndroid Build Coastguard Worker        assert (self.ipv6_packet.ipv6_header.destination_address == ipaddress.ip_address(ipv6_address))
338*cfb92d14SAndroid Build Coastguard Worker
339*cfb92d14SAndroid Build Coastguard Worker    def assertSentFromSourceAddress(self, ipv6_address):
340*cfb92d14SAndroid Build Coastguard Worker        assert (self.ipv6_packet.ipv6_header.source_address == ipaddress.ip_address(ipv6_address))
341*cfb92d14SAndroid Build Coastguard Worker
342*cfb92d14SAndroid Build Coastguard Worker    def assertSentWithHopLimit(self, hop_limit):
343*cfb92d14SAndroid Build Coastguard Worker        assert self.ipv6_packet.ipv6_header.hop_limit == hop_limit
344*cfb92d14SAndroid Build Coastguard Worker
345*cfb92d14SAndroid Build Coastguard Worker    def isMacAddressTypeLong(self):
346*cfb92d14SAndroid Build Coastguard Worker        return self.mac_header.dest_address.type == common.MacAddressType.LONG
347*cfb92d14SAndroid Build Coastguard Worker
348*cfb92d14SAndroid Build Coastguard Worker    def get_dst_udp_port(self):
349*cfb92d14SAndroid Build Coastguard Worker        assert isinstance(self.ipv6_packet.upper_layer_protocol, ipv6.UDPDatagram)
350*cfb92d14SAndroid Build Coastguard Worker        return self.ipv6_packet.upper_layer_protocol.header.dst_port
351*cfb92d14SAndroid Build Coastguard Worker
352*cfb92d14SAndroid Build Coastguard Worker    def is_data_poll(self):
353*cfb92d14SAndroid Build Coastguard Worker        return self._type == MessageType.COMMAND and \
354*cfb92d14SAndroid Build Coastguard Worker            self._mac_header.command_type == mac802154.MacHeader.CommandIdentifier.DATA_REQUEST
355*cfb92d14SAndroid Build Coastguard Worker
356*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
357*cfb92d14SAndroid Build Coastguard Worker        if (self.type == MessageType.DTLS and self.dtls.content_type == dtls.ContentType.HANDSHAKE):
358*cfb92d14SAndroid Build Coastguard Worker            return "Message(type={})".format(str(self.dtls.handshake_type))
359*cfb92d14SAndroid Build Coastguard Worker        return "Message(type={})".format(MessageType(self.type).name)
360*cfb92d14SAndroid Build Coastguard Worker
361*cfb92d14SAndroid Build Coastguard Worker
362*cfb92d14SAndroid Build Coastguard Workerclass MessagesSet(object):
363*cfb92d14SAndroid Build Coastguard Worker
364*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, messages, commissioning_messages=()):
365*cfb92d14SAndroid Build Coastguard Worker        self._messages = messages
366*cfb92d14SAndroid Build Coastguard Worker        self._commissioning_messages = commissioning_messages
367*cfb92d14SAndroid Build Coastguard Worker
368*cfb92d14SAndroid Build Coastguard Worker    @property
369*cfb92d14SAndroid Build Coastguard Worker    def messages(self):
370*cfb92d14SAndroid Build Coastguard Worker        return self._messages
371*cfb92d14SAndroid Build Coastguard Worker
372*cfb92d14SAndroid Build Coastguard Worker    @property
373*cfb92d14SAndroid Build Coastguard Worker    def commissioning_messages(self):
374*cfb92d14SAndroid Build Coastguard Worker        return self._commissioning_messages
375*cfb92d14SAndroid Build Coastguard Worker
376*cfb92d14SAndroid Build Coastguard Worker    def next_data_poll(self):
377*cfb92d14SAndroid Build Coastguard Worker        while True:
378*cfb92d14SAndroid Build Coastguard Worker            message = self.next_message_of(MessageType.COMMAND, False)
379*cfb92d14SAndroid Build Coastguard Worker            if not message:
380*cfb92d14SAndroid Build Coastguard Worker                break
381*cfb92d14SAndroid Build Coastguard Worker            elif message.is_data_poll():
382*cfb92d14SAndroid Build Coastguard Worker                return message
383*cfb92d14SAndroid Build Coastguard Worker
384*cfb92d14SAndroid Build Coastguard Worker    def next_coap_message(self, code, uri_path=None, assert_enabled=True):
385*cfb92d14SAndroid Build Coastguard Worker        message = None
386*cfb92d14SAndroid Build Coastguard Worker
387*cfb92d14SAndroid Build Coastguard Worker        while self.messages:
388*cfb92d14SAndroid Build Coastguard Worker            m = self.messages.pop(0)
389*cfb92d14SAndroid Build Coastguard Worker
390*cfb92d14SAndroid Build Coastguard Worker            if m.type != MessageType.COAP:
391*cfb92d14SAndroid Build Coastguard Worker                continue
392*cfb92d14SAndroid Build Coastguard Worker
393*cfb92d14SAndroid Build Coastguard Worker            if uri_path is not None and m.coap.uri_path != uri_path:
394*cfb92d14SAndroid Build Coastguard Worker                continue
395*cfb92d14SAndroid Build Coastguard Worker
396*cfb92d14SAndroid Build Coastguard Worker            else:
397*cfb92d14SAndroid Build Coastguard Worker                if not m.coap.code.is_equal_dotted(code):
398*cfb92d14SAndroid Build Coastguard Worker                    continue
399*cfb92d14SAndroid Build Coastguard Worker
400*cfb92d14SAndroid Build Coastguard Worker            message = m
401*cfb92d14SAndroid Build Coastguard Worker            break
402*cfb92d14SAndroid Build Coastguard Worker
403*cfb92d14SAndroid Build Coastguard Worker        if assert_enabled:
404*cfb92d14SAndroid Build Coastguard Worker            assert (message is not None), "Could not find CoapMessage with code: {}".format(code)
405*cfb92d14SAndroid Build Coastguard Worker
406*cfb92d14SAndroid Build Coastguard Worker        return message
407*cfb92d14SAndroid Build Coastguard Worker
408*cfb92d14SAndroid Build Coastguard Worker    def last_mle_message(self, command_type, assert_enabled=True):
409*cfb92d14SAndroid Build Coastguard Worker        """Get the last Mle Message with specified type from existing capture.
410*cfb92d14SAndroid Build Coastguard Worker
411*cfb92d14SAndroid Build Coastguard Worker        Args:
412*cfb92d14SAndroid Build Coastguard Worker            command_type: the specified mle type.
413*cfb92d14SAndroid Build Coastguard Worker            assert_enabled: interrupt or not when get the mle.
414*cfb92d14SAndroid Build Coastguard Worker
415*cfb92d14SAndroid Build Coastguard Worker        Returns:
416*cfb92d14SAndroid Build Coastguard Worker            message.Message: the last Mle Message with specified type.
417*cfb92d14SAndroid Build Coastguard Worker        """
418*cfb92d14SAndroid Build Coastguard Worker        message = None
419*cfb92d14SAndroid Build Coastguard Worker        size = len(self.messages)
420*cfb92d14SAndroid Build Coastguard Worker
421*cfb92d14SAndroid Build Coastguard Worker        for i in range(size - 1, -1, -1):
422*cfb92d14SAndroid Build Coastguard Worker            m = self.messages[i]
423*cfb92d14SAndroid Build Coastguard Worker
424*cfb92d14SAndroid Build Coastguard Worker            if m.type != MessageType.MLE:
425*cfb92d14SAndroid Build Coastguard Worker                continue
426*cfb92d14SAndroid Build Coastguard Worker
427*cfb92d14SAndroid Build Coastguard Worker            # for command_type in command_types:
428*cfb92d14SAndroid Build Coastguard Worker            if m.mle.command.type == command_type:
429*cfb92d14SAndroid Build Coastguard Worker                message = m
430*cfb92d14SAndroid Build Coastguard Worker                break
431*cfb92d14SAndroid Build Coastguard Worker
432*cfb92d14SAndroid Build Coastguard Worker        if assert_enabled:
433*cfb92d14SAndroid Build Coastguard Worker            assert (message is not None), "Could not find MleMessage with type: {}".format(command_type)
434*cfb92d14SAndroid Build Coastguard Worker
435*cfb92d14SAndroid Build Coastguard Worker        return message
436*cfb92d14SAndroid Build Coastguard Worker
437*cfb92d14SAndroid Build Coastguard Worker    def next_mle_message(self, command_type, assert_enabled=True, sent_to_node=None):
438*cfb92d14SAndroid Build Coastguard Worker        message = self.next_mle_message_of_one_of_command_types(command_type)
439*cfb92d14SAndroid Build Coastguard Worker
440*cfb92d14SAndroid Build Coastguard Worker        if assert_enabled:
441*cfb92d14SAndroid Build Coastguard Worker            assert (message is not None), "Could not find MleMessage of the type: {}".format(command_type)
442*cfb92d14SAndroid Build Coastguard Worker
443*cfb92d14SAndroid Build Coastguard Worker        if sent_to_node is not None:
444*cfb92d14SAndroid Build Coastguard Worker            message.assertSentToNode(sent_to_node)
445*cfb92d14SAndroid Build Coastguard Worker
446*cfb92d14SAndroid Build Coastguard Worker        return message
447*cfb92d14SAndroid Build Coastguard Worker
448*cfb92d14SAndroid Build Coastguard Worker    def next_mle_message_of_one_of_command_types(self, *command_types):
449*cfb92d14SAndroid Build Coastguard Worker        message = None
450*cfb92d14SAndroid Build Coastguard Worker
451*cfb92d14SAndroid Build Coastguard Worker        while self.messages:
452*cfb92d14SAndroid Build Coastguard Worker            m = self.messages.pop(0)
453*cfb92d14SAndroid Build Coastguard Worker
454*cfb92d14SAndroid Build Coastguard Worker            if m.type != MessageType.MLE:
455*cfb92d14SAndroid Build Coastguard Worker                continue
456*cfb92d14SAndroid Build Coastguard Worker
457*cfb92d14SAndroid Build Coastguard Worker            command_found = False
458*cfb92d14SAndroid Build Coastguard Worker
459*cfb92d14SAndroid Build Coastguard Worker            for command_type in command_types:
460*cfb92d14SAndroid Build Coastguard Worker                if m.mle.command.type == command_type:
461*cfb92d14SAndroid Build Coastguard Worker                    command_found = True
462*cfb92d14SAndroid Build Coastguard Worker                    break
463*cfb92d14SAndroid Build Coastguard Worker
464*cfb92d14SAndroid Build Coastguard Worker            if command_found:
465*cfb92d14SAndroid Build Coastguard Worker                message = m
466*cfb92d14SAndroid Build Coastguard Worker                break
467*cfb92d14SAndroid Build Coastguard Worker
468*cfb92d14SAndroid Build Coastguard Worker        return message
469*cfb92d14SAndroid Build Coastguard Worker
470*cfb92d14SAndroid Build Coastguard Worker    def next_message(self, assert_enabled=True):
471*cfb92d14SAndroid Build Coastguard Worker        message = self.messages.pop(0)
472*cfb92d14SAndroid Build Coastguard Worker        if assert_enabled:
473*cfb92d14SAndroid Build Coastguard Worker            assert message is not None, "Could not find next Message"
474*cfb92d14SAndroid Build Coastguard Worker        return message
475*cfb92d14SAndroid Build Coastguard Worker
476*cfb92d14SAndroid Build Coastguard Worker    def next_message_of(self, message_type, assert_enabled=True):
477*cfb92d14SAndroid Build Coastguard Worker        message = None
478*cfb92d14SAndroid Build Coastguard Worker
479*cfb92d14SAndroid Build Coastguard Worker        while self.messages:
480*cfb92d14SAndroid Build Coastguard Worker            m = self.messages.pop(0)
481*cfb92d14SAndroid Build Coastguard Worker            if m.type != message_type:
482*cfb92d14SAndroid Build Coastguard Worker                continue
483*cfb92d14SAndroid Build Coastguard Worker
484*cfb92d14SAndroid Build Coastguard Worker            message = m
485*cfb92d14SAndroid Build Coastguard Worker            break
486*cfb92d14SAndroid Build Coastguard Worker
487*cfb92d14SAndroid Build Coastguard Worker        if assert_enabled:
488*cfb92d14SAndroid Build Coastguard Worker            assert (message is not None), "Could not find Message of the type: {}".format(message_type)
489*cfb92d14SAndroid Build Coastguard Worker
490*cfb92d14SAndroid Build Coastguard Worker        return message
491*cfb92d14SAndroid Build Coastguard Worker
492*cfb92d14SAndroid Build Coastguard Worker    def next_data_message(self):
493*cfb92d14SAndroid Build Coastguard Worker        return self.next_message_of(MessageType.DATA)
494*cfb92d14SAndroid Build Coastguard Worker
495*cfb92d14SAndroid Build Coastguard Worker    def next_command_message(self):
496*cfb92d14SAndroid Build Coastguard Worker        return self.next_message_of(MessageType.COMMAND)
497*cfb92d14SAndroid Build Coastguard Worker
498*cfb92d14SAndroid Build Coastguard Worker    def next_dtls_message(self, content_type, handshake_type=None):
499*cfb92d14SAndroid Build Coastguard Worker        while self.messages:
500*cfb92d14SAndroid Build Coastguard Worker            msg = self.messages.pop(0)
501*cfb92d14SAndroid Build Coastguard Worker            if msg.type != MessageType.DTLS:
502*cfb92d14SAndroid Build Coastguard Worker                continue
503*cfb92d14SAndroid Build Coastguard Worker            if msg.dtls.content_type != content_type:
504*cfb92d14SAndroid Build Coastguard Worker                continue
505*cfb92d14SAndroid Build Coastguard Worker            if (content_type == dtls.ContentType.HANDSHAKE and msg.dtls.handshake_type != handshake_type):
506*cfb92d14SAndroid Build Coastguard Worker                continue
507*cfb92d14SAndroid Build Coastguard Worker            return msg
508*cfb92d14SAndroid Build Coastguard Worker
509*cfb92d14SAndroid Build Coastguard Worker        t = (handshake_type if content_type == dtls.ContentType.HANDSHAKE else content_type)
510*cfb92d14SAndroid Build Coastguard Worker        raise ValueError("Could not find DTLS message of type: {}".format(str(t)))
511*cfb92d14SAndroid Build Coastguard Worker
512*cfb92d14SAndroid Build Coastguard Worker    def contains_icmp_message(self):
513*cfb92d14SAndroid Build Coastguard Worker        for m in self.messages:
514*cfb92d14SAndroid Build Coastguard Worker            if m.type == MessageType.ICMP:
515*cfb92d14SAndroid Build Coastguard Worker                return True
516*cfb92d14SAndroid Build Coastguard Worker
517*cfb92d14SAndroid Build Coastguard Worker        return False
518*cfb92d14SAndroid Build Coastguard Worker
519*cfb92d14SAndroid Build Coastguard Worker    def get_icmp_message(self, icmp_type):
520*cfb92d14SAndroid Build Coastguard Worker        for m in self.messages:
521*cfb92d14SAndroid Build Coastguard Worker            if m.type != MessageType.ICMP:
522*cfb92d14SAndroid Build Coastguard Worker                continue
523*cfb92d14SAndroid Build Coastguard Worker
524*cfb92d14SAndroid Build Coastguard Worker            if m.icmp.header.type == icmp_type:
525*cfb92d14SAndroid Build Coastguard Worker                return m
526*cfb92d14SAndroid Build Coastguard Worker
527*cfb92d14SAndroid Build Coastguard Worker        return None
528*cfb92d14SAndroid Build Coastguard Worker
529*cfb92d14SAndroid Build Coastguard Worker    def contains_mle_message(self, command_type):
530*cfb92d14SAndroid Build Coastguard Worker        for m in self.messages:
531*cfb92d14SAndroid Build Coastguard Worker            if m.type != MessageType.MLE:
532*cfb92d14SAndroid Build Coastguard Worker                continue
533*cfb92d14SAndroid Build Coastguard Worker
534*cfb92d14SAndroid Build Coastguard Worker            if m.mle.command.type == command_type:
535*cfb92d14SAndroid Build Coastguard Worker                return True
536*cfb92d14SAndroid Build Coastguard Worker
537*cfb92d14SAndroid Build Coastguard Worker        return False
538*cfb92d14SAndroid Build Coastguard Worker
539*cfb92d14SAndroid Build Coastguard Worker    def does_not_contain_coap_message(self):
540*cfb92d14SAndroid Build Coastguard Worker        for m in self.messages:
541*cfb92d14SAndroid Build Coastguard Worker            if m.type != MessageType.COAP:
542*cfb92d14SAndroid Build Coastguard Worker                continue
543*cfb92d14SAndroid Build Coastguard Worker
544*cfb92d14SAndroid Build Coastguard Worker            return False
545*cfb92d14SAndroid Build Coastguard Worker
546*cfb92d14SAndroid Build Coastguard Worker        return True
547*cfb92d14SAndroid Build Coastguard Worker
548*cfb92d14SAndroid Build Coastguard Worker    def clone(self):
549*cfb92d14SAndroid Build Coastguard Worker        """Make a copy of current MessageSet.
550*cfb92d14SAndroid Build Coastguard Worker        """
551*cfb92d14SAndroid Build Coastguard Worker        return MessagesSet(self.messages[:], self.commissioning_messages[:])
552*cfb92d14SAndroid Build Coastguard Worker
553*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
554*cfb92d14SAndroid Build Coastguard Worker        return str(self.messages)
555*cfb92d14SAndroid Build Coastguard Worker
556*cfb92d14SAndroid Build Coastguard Worker
557*cfb92d14SAndroid Build Coastguard Workerclass MessageFactory:
558*cfb92d14SAndroid Build Coastguard Worker
559*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, lowpan_parser):
560*cfb92d14SAndroid Build Coastguard Worker        self._lowpan_parser = lowpan_parser
561*cfb92d14SAndroid Build Coastguard Worker
562*cfb92d14SAndroid Build Coastguard Worker    def _add_device_descriptors(self, message):
563*cfb92d14SAndroid Build Coastguard Worker        for tlv in message.mle.command.tlvs:
564*cfb92d14SAndroid Build Coastguard Worker
565*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, mle.SourceAddress):
566*cfb92d14SAndroid Build Coastguard Worker                mac802154.DeviceDescriptors.add(tlv.address, message.mac_header.src_address)
567*cfb92d14SAndroid Build Coastguard Worker
568*cfb92d14SAndroid Build Coastguard Worker            if isinstance(tlv, mle.Address16):
569*cfb92d14SAndroid Build Coastguard Worker                mac802154.DeviceDescriptors.add(tlv.address, message.mac_header.dest_address)
570*cfb92d14SAndroid Build Coastguard Worker
571*cfb92d14SAndroid Build Coastguard Worker    def _parse_mac_frame(self, data):
572*cfb92d14SAndroid Build Coastguard Worker        mac_frame = mac802154.MacFrame()
573*cfb92d14SAndroid Build Coastguard Worker        mac_frame.parse(data)
574*cfb92d14SAndroid Build Coastguard Worker        return mac_frame
575*cfb92d14SAndroid Build Coastguard Worker
576*cfb92d14SAndroid Build Coastguard Worker    def set_lowpan_context(self, cid, prefix):
577*cfb92d14SAndroid Build Coastguard Worker        self._lowpan_parser.set_lowpan_context(cid, prefix)
578*cfb92d14SAndroid Build Coastguard Worker
579*cfb92d14SAndroid Build Coastguard Worker    def create(self, data):
580*cfb92d14SAndroid Build Coastguard Worker        try:
581*cfb92d14SAndroid Build Coastguard Worker            message = Message()
582*cfb92d14SAndroid Build Coastguard Worker            message.channel = struct.unpack(">B", data.read(1))
583*cfb92d14SAndroid Build Coastguard Worker
584*cfb92d14SAndroid Build Coastguard Worker            # Parse MAC header
585*cfb92d14SAndroid Build Coastguard Worker            mac_frame = self._parse_mac_frame(data)
586*cfb92d14SAndroid Build Coastguard Worker            message.mac_header = mac_frame.header
587*cfb92d14SAndroid Build Coastguard Worker
588*cfb92d14SAndroid Build Coastguard Worker            if message.mac_header.frame_type != mac802154.MacHeader.FrameType.DATA:
589*cfb92d14SAndroid Build Coastguard Worker                return [message]
590*cfb92d14SAndroid Build Coastguard Worker
591*cfb92d14SAndroid Build Coastguard Worker            message_info = common.MessageInfo()
592*cfb92d14SAndroid Build Coastguard Worker            message_info.source_mac_address = message.mac_header.src_address
593*cfb92d14SAndroid Build Coastguard Worker            message_info.destination_mac_address = message.mac_header.dest_address
594*cfb92d14SAndroid Build Coastguard Worker
595*cfb92d14SAndroid Build Coastguard Worker            # Create stream with 6LoWPAN datagram
596*cfb92d14SAndroid Build Coastguard Worker            lowpan_payload = io.BytesIO(mac_frame.payload.data)
597*cfb92d14SAndroid Build Coastguard Worker
598*cfb92d14SAndroid Build Coastguard Worker            ipv6_packet = self._lowpan_parser.parse(lowpan_payload, message_info)
599*cfb92d14SAndroid Build Coastguard Worker            if ipv6_packet is None:
600*cfb92d14SAndroid Build Coastguard Worker                return [message]
601*cfb92d14SAndroid Build Coastguard Worker
602*cfb92d14SAndroid Build Coastguard Worker            message.ipv6_packet = ipv6_packet
603*cfb92d14SAndroid Build Coastguard Worker
604*cfb92d14SAndroid Build Coastguard Worker            if message.type == MessageType.MLE:
605*cfb92d14SAndroid Build Coastguard Worker                self._add_device_descriptors(message)
606*cfb92d14SAndroid Build Coastguard Worker
607*cfb92d14SAndroid Build Coastguard Worker            return message.try_extract_dtls_messages()
608*cfb92d14SAndroid Build Coastguard Worker
609*cfb92d14SAndroid Build Coastguard Worker        except mac802154.KeyIdMode0Exception:
610*cfb92d14SAndroid Build Coastguard Worker            print('Received packet with key_id_mode = 0, cannot be handled in test scripts')
611*cfb92d14SAndroid Build Coastguard Worker            raise DropPacketException
612