xref: /aosp_15_r20/external/openthread/tests/scripts/thread-cert/mac802154.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 Worker    This module provides simple 802.15.4 MAC parser.
31*cfb92d14SAndroid Build Coastguard Worker"""
32*cfb92d14SAndroid Build Coastguard Worker
33*cfb92d14SAndroid Build Coastguard Workerimport io
34*cfb92d14SAndroid Build Coastguard Workerimport struct
35*cfb92d14SAndroid Build Coastguard Worker
36*cfb92d14SAndroid Build Coastguard Workerimport config
37*cfb92d14SAndroid Build Coastguard Workerfrom common import MacAddress, MacAddressType, MessageInfo
38*cfb92d14SAndroid Build Coastguard Workerfrom net_crypto import (
39*cfb92d14SAndroid Build Coastguard Worker    AuxiliarySecurityHeader,
40*cfb92d14SAndroid Build Coastguard Worker    CryptoEngine,
41*cfb92d14SAndroid Build Coastguard Worker    MacCryptoMaterialCreator,
42*cfb92d14SAndroid Build Coastguard Worker)
43*cfb92d14SAndroid Build Coastguard Worker
44*cfb92d14SAndroid Build Coastguard Worker
45*cfb92d14SAndroid Build Coastguard Workerclass KeyIdMode0Exception(Exception):
46*cfb92d14SAndroid Build Coastguard Worker    """
47*cfb92d14SAndroid Build Coastguard Worker    Raised when key id mode of packet is 0.
48*cfb92d14SAndroid Build Coastguard Worker    Such packet wouldn't be handled in test scripts,
49*cfb92d14SAndroid Build Coastguard Worker    but it's not abnormal behavior.
50*cfb92d14SAndroid Build Coastguard Worker    """
51*cfb92d14SAndroid Build Coastguard Worker    pass
52*cfb92d14SAndroid Build Coastguard Worker
53*cfb92d14SAndroid Build Coastguard Worker
54*cfb92d14SAndroid Build Coastguard Workerclass DeviceDescriptors:
55*cfb92d14SAndroid Build Coastguard Worker    """Class representing 802.15.4 Device Descriptors."""
56*cfb92d14SAndroid Build Coastguard Worker
57*cfb92d14SAndroid Build Coastguard Worker    device_descriptors = {}
58*cfb92d14SAndroid Build Coastguard Worker
59*cfb92d14SAndroid Build Coastguard Worker    @classmethod
60*cfb92d14SAndroid Build Coastguard Worker    def add(cls, short_address, extended_address):
61*cfb92d14SAndroid Build Coastguard Worker        short_address = cls._get_short_address_value(short_address)
62*cfb92d14SAndroid Build Coastguard Worker        cls.device_descriptors[short_address] = extended_address
63*cfb92d14SAndroid Build Coastguard Worker
64*cfb92d14SAndroid Build Coastguard Worker    @classmethod
65*cfb92d14SAndroid Build Coastguard Worker    def get_extended(cls, short_address):
66*cfb92d14SAndroid Build Coastguard Worker        short_address = cls._get_short_address_value(short_address)
67*cfb92d14SAndroid Build Coastguard Worker        return cls.device_descriptors[short_address]
68*cfb92d14SAndroid Build Coastguard Worker
69*cfb92d14SAndroid Build Coastguard Worker    @staticmethod
70*cfb92d14SAndroid Build Coastguard Worker    def _get_short_address_value(short_address):
71*cfb92d14SAndroid Build Coastguard Worker        if isinstance(short_address, MacAddress):
72*cfb92d14SAndroid Build Coastguard Worker            short_address = short_address.rloc
73*cfb92d14SAndroid Build Coastguard Worker        return short_address
74*cfb92d14SAndroid Build Coastguard Worker
75*cfb92d14SAndroid Build Coastguard Worker
76*cfb92d14SAndroid Build Coastguard Workerclass InformationElement:
77*cfb92d14SAndroid Build Coastguard Worker    """Class representing 802.15.4 MAC Information Element."""
78*cfb92d14SAndroid Build Coastguard Worker
79*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, id, length, content):
80*cfb92d14SAndroid Build Coastguard Worker        self._id = id
81*cfb92d14SAndroid Build Coastguard Worker        self._length = length
82*cfb92d14SAndroid Build Coastguard Worker        self._content = content
83*cfb92d14SAndroid Build Coastguard Worker
84*cfb92d14SAndroid Build Coastguard Worker    @property
85*cfb92d14SAndroid Build Coastguard Worker    def id(self):
86*cfb92d14SAndroid Build Coastguard Worker        return self._id
87*cfb92d14SAndroid Build Coastguard Worker
88*cfb92d14SAndroid Build Coastguard Worker    @property
89*cfb92d14SAndroid Build Coastguard Worker    def length(self):
90*cfb92d14SAndroid Build Coastguard Worker        return self._length
91*cfb92d14SAndroid Build Coastguard Worker
92*cfb92d14SAndroid Build Coastguard Worker    @property
93*cfb92d14SAndroid Build Coastguard Worker    def content(self):
94*cfb92d14SAndroid Build Coastguard Worker        return self._content
95*cfb92d14SAndroid Build Coastguard Worker
96*cfb92d14SAndroid Build Coastguard Worker
97*cfb92d14SAndroid Build Coastguard Workerclass MacHeader:
98*cfb92d14SAndroid Build Coastguard Worker    """Class representing 802.15.4 MAC header."""
99*cfb92d14SAndroid Build Coastguard Worker
100*cfb92d14SAndroid Build Coastguard Worker    class FrameType:
101*cfb92d14SAndroid Build Coastguard Worker        BEACON = 0
102*cfb92d14SAndroid Build Coastguard Worker        DATA = 1
103*cfb92d14SAndroid Build Coastguard Worker        ACK = 2
104*cfb92d14SAndroid Build Coastguard Worker        COMMAND = 3
105*cfb92d14SAndroid Build Coastguard Worker
106*cfb92d14SAndroid Build Coastguard Worker    class AddressMode:
107*cfb92d14SAndroid Build Coastguard Worker        NOT_PRESENT = 0
108*cfb92d14SAndroid Build Coastguard Worker        SHORT = 2
109*cfb92d14SAndroid Build Coastguard Worker        EXTENDED = 3
110*cfb92d14SAndroid Build Coastguard Worker
111*cfb92d14SAndroid Build Coastguard Worker    class CommandIdentifier:
112*cfb92d14SAndroid Build Coastguard Worker        DATA_REQUEST = 4
113*cfb92d14SAndroid Build Coastguard Worker
114*cfb92d14SAndroid Build Coastguard Worker    def __init__(
115*cfb92d14SAndroid Build Coastguard Worker        self,
116*cfb92d14SAndroid Build Coastguard Worker        frame_type,
117*cfb92d14SAndroid Build Coastguard Worker        frame_pending,
118*cfb92d14SAndroid Build Coastguard Worker        ack_request,
119*cfb92d14SAndroid Build Coastguard Worker        frame_version,
120*cfb92d14SAndroid Build Coastguard Worker        seq,
121*cfb92d14SAndroid Build Coastguard Worker        dest_pan_id=None,
122*cfb92d14SAndroid Build Coastguard Worker        dest_address=None,
123*cfb92d14SAndroid Build Coastguard Worker        src_pan_id=None,
124*cfb92d14SAndroid Build Coastguard Worker        src_address=None,
125*cfb92d14SAndroid Build Coastguard Worker        command_type=None,
126*cfb92d14SAndroid Build Coastguard Worker        aux_sec_header=None,
127*cfb92d14SAndroid Build Coastguard Worker        mic=None,
128*cfb92d14SAndroid Build Coastguard Worker        fcs=None,
129*cfb92d14SAndroid Build Coastguard Worker    ):
130*cfb92d14SAndroid Build Coastguard Worker
131*cfb92d14SAndroid Build Coastguard Worker        self.frame_type = frame_type
132*cfb92d14SAndroid Build Coastguard Worker        self.frame_pending = frame_pending
133*cfb92d14SAndroid Build Coastguard Worker        self.ack_request = ack_request
134*cfb92d14SAndroid Build Coastguard Worker        self.frame_version = frame_version
135*cfb92d14SAndroid Build Coastguard Worker        self.seq = seq
136*cfb92d14SAndroid Build Coastguard Worker
137*cfb92d14SAndroid Build Coastguard Worker        self.dest_pan_id = dest_pan_id
138*cfb92d14SAndroid Build Coastguard Worker        self.dest_address = dest_address
139*cfb92d14SAndroid Build Coastguard Worker        self.src_pan_id = src_pan_id
140*cfb92d14SAndroid Build Coastguard Worker        self.src_address = src_address
141*cfb92d14SAndroid Build Coastguard Worker        self.command_type = command_type
142*cfb92d14SAndroid Build Coastguard Worker
143*cfb92d14SAndroid Build Coastguard Worker        self.aux_sec_header = aux_sec_header
144*cfb92d14SAndroid Build Coastguard Worker        self.mic = mic
145*cfb92d14SAndroid Build Coastguard Worker
146*cfb92d14SAndroid Build Coastguard Worker        self.fcs = fcs
147*cfb92d14SAndroid Build Coastguard Worker
148*cfb92d14SAndroid Build Coastguard Worker
149*cfb92d14SAndroid Build Coastguard Workerclass MacPayload:
150*cfb92d14SAndroid Build Coastguard Worker    """Class representing 802.15.4 MAC payload."""
151*cfb92d14SAndroid Build Coastguard Worker
152*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, data):
153*cfb92d14SAndroid Build Coastguard Worker        self.data = bytearray(data)
154*cfb92d14SAndroid Build Coastguard Worker
155*cfb92d14SAndroid Build Coastguard Worker
156*cfb92d14SAndroid Build Coastguard Workerclass MacFrame:
157*cfb92d14SAndroid Build Coastguard Worker    """Class representing 802.15.4 MAC frame."""
158*cfb92d14SAndroid Build Coastguard Worker
159*cfb92d14SAndroid Build Coastguard Worker    IEEE802154_HEADER_IE_TYPE_MASK = 0x8000
160*cfb92d14SAndroid Build Coastguard Worker    IEEE802154_HEADER_IE_ID_MASK = 0x7F80
161*cfb92d14SAndroid Build Coastguard Worker    IEEE802154_HEADER_IE_LENGTH_MASK = 0x007F
162*cfb92d14SAndroid Build Coastguard Worker
163*cfb92d14SAndroid Build Coastguard Worker    IEEE802154_HEADER_IE_HT1 = 0x7E
164*cfb92d14SAndroid Build Coastguard Worker    IEEE802154_HEADER_IE_HT2 = 0x7F
165*cfb92d14SAndroid Build Coastguard Worker
166*cfb92d14SAndroid Build Coastguard Worker    IEEE802154_VERSION_2015 = 0x02
167*cfb92d14SAndroid Build Coastguard Worker
168*cfb92d14SAndroid Build Coastguard Worker    def parse(self, data):
169*cfb92d14SAndroid Build Coastguard Worker        """Parse a MAC 802.15.4 frame
170*cfb92d14SAndroid Build Coastguard Worker
171*cfb92d14SAndroid Build Coastguard Worker        Format of MAC 802.15.4 Frame:
172*cfb92d14SAndroid Build Coastguard Worker        | Frame Header | ASH | IE | Frame Payload | MIC | FCS |
173*cfb92d14SAndroid Build Coastguard Worker
174*cfb92d14SAndroid Build Coastguard Worker        Frame Header:  Frame Control | Sequence Number | Addressing Field
175*cfb92d14SAndroid Build Coastguard Worker        ASH: Auxiliary Security Header (optional)
176*cfb92d14SAndroid Build Coastguard Worker        IE: Header IE | Payload IE (optional)
177*cfb92d14SAndroid Build Coastguard Worker        Frame Payload: Data payload (optional)
178*cfb92d14SAndroid Build Coastguard Worker        MIC: To authenticate the frame (optional)
179*cfb92d14SAndroid Build Coastguard Worker
180*cfb92d14SAndroid Build Coastguard Worker        In the parsing process, Frame Header is parsed first. Then it can be
181*cfb92d14SAndroid Build Coastguard Worker        determined if security is enabled for this frame. If it's enabled,
182*cfb92d14SAndroid Build Coastguard Worker        then ASH should be parsed.
183*cfb92d14SAndroid Build Coastguard Worker        After that, go directly to the end to parse FCS first instead
184*cfb92d14SAndroid Build Coastguard Worker        of parsing IE or Frame Payload. This is because sometimes, IE doesn't
185*cfb92d14SAndroid Build Coastguard Worker        have a termination IE and parsing needs to know the start of MIC to determine
186*cfb92d14SAndroid Build Coastguard Worker        where's the end of IEs(In such cases there are no payload).
187*cfb92d14SAndroid Build Coastguard Worker        After parsing FCS, MIC is parsed if security is enabled.
188*cfb92d14SAndroid Build Coastguard Worker        Then the end of IE(or payload) is known. And at last IEs and payload
189*cfb92d14SAndroid Build Coastguard Worker        are parsed.
190*cfb92d14SAndroid Build Coastguard Worker        And after parsing everything, build MacHeader and MacPayload with
191*cfb92d14SAndroid Build Coastguard Worker        the things parsed.
192*cfb92d14SAndroid Build Coastguard Worker        """
193*cfb92d14SAndroid Build Coastguard Worker        mhr_start = data.tell()
194*cfb92d14SAndroid Build Coastguard Worker
195*cfb92d14SAndroid Build Coastguard Worker        fc, seq = struct.unpack("<HB", data.read(3))
196*cfb92d14SAndroid Build Coastguard Worker
197*cfb92d14SAndroid Build Coastguard Worker        frame_type = fc & 0x0007
198*cfb92d14SAndroid Build Coastguard Worker        security_enabled = bool(fc & 0x0008)
199*cfb92d14SAndroid Build Coastguard Worker        frame_pending = bool(fc & 0x0010)
200*cfb92d14SAndroid Build Coastguard Worker        ack_request = bool(fc & 0x0020)
201*cfb92d14SAndroid Build Coastguard Worker        panid_compression = bool(fc & 0x0040)
202*cfb92d14SAndroid Build Coastguard Worker        dest_addr_mode = (fc & 0x0C00) >> 10
203*cfb92d14SAndroid Build Coastguard Worker        frame_version = (fc & 0x3000) >> 12
204*cfb92d14SAndroid Build Coastguard Worker        source_addr_mode = (fc & 0xC000) >> 14
205*cfb92d14SAndroid Build Coastguard Worker        ie_present = bool(fc & 0x0200)
206*cfb92d14SAndroid Build Coastguard Worker
207*cfb92d14SAndroid Build Coastguard Worker        if frame_type == MacHeader.FrameType.ACK:
208*cfb92d14SAndroid Build Coastguard Worker            fcs = self._parse_fcs(data, data.tell())
209*cfb92d14SAndroid Build Coastguard Worker            self.header = MacHeader(
210*cfb92d14SAndroid Build Coastguard Worker                frame_type,
211*cfb92d14SAndroid Build Coastguard Worker                frame_pending,
212*cfb92d14SAndroid Build Coastguard Worker                ack_request,
213*cfb92d14SAndroid Build Coastguard Worker                frame_version,
214*cfb92d14SAndroid Build Coastguard Worker                seq,
215*cfb92d14SAndroid Build Coastguard Worker                fcs=fcs,
216*cfb92d14SAndroid Build Coastguard Worker            )
217*cfb92d14SAndroid Build Coastguard Worker            self.payload = None
218*cfb92d14SAndroid Build Coastguard Worker            return
219*cfb92d14SAndroid Build Coastguard Worker
220*cfb92d14SAndroid Build Coastguard Worker        dest_addr_present = dest_addr_mode != MacHeader.AddressMode.NOT_PRESENT
221*cfb92d14SAndroid Build Coastguard Worker        src_addr_present = source_addr_mode != MacHeader.AddressMode.NOT_PRESENT
222*cfb92d14SAndroid Build Coastguard Worker
223*cfb92d14SAndroid Build Coastguard Worker        if frame_version < 2:
224*cfb92d14SAndroid Build Coastguard Worker            dest_pan_present = dest_addr_present
225*cfb92d14SAndroid Build Coastguard Worker        else:
226*cfb92d14SAndroid Build Coastguard Worker            dest_pan_present = True
227*cfb92d14SAndroid Build Coastguard Worker            if not src_addr_present:
228*cfb92d14SAndroid Build Coastguard Worker                dest_pan_present = src_pan_present != panid_compression
229*cfb92d14SAndroid Build Coastguard Worker            elif not dest_addr_present:
230*cfb92d14SAndroid Build Coastguard Worker                dest_pan_present = False
231*cfb92d14SAndroid Build Coastguard Worker            else:
232*cfb92d14SAndroid Build Coastguard Worker                if dest_addr_mode == MacHeader.AddressMode.EXTENDED and source_addr_mode == MacHeader.AddressMode.EXTENDED and panid_compression:
233*cfb92d14SAndroid Build Coastguard Worker                    dest_pan_present = False
234*cfb92d14SAndroid Build Coastguard Worker
235*cfb92d14SAndroid Build Coastguard Worker        if dest_pan_present:
236*cfb92d14SAndroid Build Coastguard Worker            dest_pan_id = struct.unpack("<H", data.read(2))[0]
237*cfb92d14SAndroid Build Coastguard Worker        else:
238*cfb92d14SAndroid Build Coastguard Worker            dest_pan_id = None
239*cfb92d14SAndroid Build Coastguard Worker
240*cfb92d14SAndroid Build Coastguard Worker        dest_address = self._parse_address(data, dest_addr_mode)
241*cfb92d14SAndroid Build Coastguard Worker
242*cfb92d14SAndroid Build Coastguard Worker        src_pan_present = not panid_compression
243*cfb92d14SAndroid Build Coastguard Worker        while src_pan_present:
244*cfb92d14SAndroid Build Coastguard Worker            if frame_version < 2:
245*cfb92d14SAndroid Build Coastguard Worker                break
246*cfb92d14SAndroid Build Coastguard Worker            if frame_version == 3:
247*cfb92d14SAndroid Build Coastguard Worker                assert False
248*cfb92d14SAndroid Build Coastguard Worker            if dest_addr_mode == 0:
249*cfb92d14SAndroid Build Coastguard Worker                break
250*cfb92d14SAndroid Build Coastguard Worker            if dest_addr_mode == 2:
251*cfb92d14SAndroid Build Coastguard Worker                break
252*cfb92d14SAndroid Build Coastguard Worker            if dest_addr_mode == 3 and source_addr_mode == 2:
253*cfb92d14SAndroid Build Coastguard Worker                break
254*cfb92d14SAndroid Build Coastguard Worker            src_pan_present = False
255*cfb92d14SAndroid Build Coastguard Worker
256*cfb92d14SAndroid Build Coastguard Worker        if src_pan_present:
257*cfb92d14SAndroid Build Coastguard Worker            src_pan_id = struct.unpack("<H", data.read(2))[0]
258*cfb92d14SAndroid Build Coastguard Worker        else:
259*cfb92d14SAndroid Build Coastguard Worker            src_pan_id = dest_pan_id
260*cfb92d14SAndroid Build Coastguard Worker
261*cfb92d14SAndroid Build Coastguard Worker        src_address = self._parse_address(data, source_addr_mode)
262*cfb92d14SAndroid Build Coastguard Worker
263*cfb92d14SAndroid Build Coastguard Worker        mhr_end = data.tell()
264*cfb92d14SAndroid Build Coastguard Worker
265*cfb92d14SAndroid Build Coastguard Worker        if security_enabled:
266*cfb92d14SAndroid Build Coastguard Worker            aux_sec_header = self._parse_aux_sec_header(data)
267*cfb92d14SAndroid Build Coastguard Worker            aux_sec_header_end = data.tell()
268*cfb92d14SAndroid Build Coastguard Worker        else:
269*cfb92d14SAndroid Build Coastguard Worker            aux_sec_header = None
270*cfb92d14SAndroid Build Coastguard Worker
271*cfb92d14SAndroid Build Coastguard Worker        # Record the beginning position of header IE.
272*cfb92d14SAndroid Build Coastguard Worker        # Or the position of payload if there is no header IE.
273*cfb92d14SAndroid Build Coastguard Worker        cur_pos = data.tell()
274*cfb92d14SAndroid Build Coastguard Worker        header_ie_start = cur_pos
275*cfb92d14SAndroid Build Coastguard Worker
276*cfb92d14SAndroid Build Coastguard Worker        data.seek(-2, io.SEEK_END)
277*cfb92d14SAndroid Build Coastguard Worker        fcs_start = data.tell()
278*cfb92d14SAndroid Build Coastguard Worker        fcs = self._parse_fcs(data, fcs_start)
279*cfb92d14SAndroid Build Coastguard Worker
280*cfb92d14SAndroid Build Coastguard Worker        data.seek(fcs_start)
281*cfb92d14SAndroid Build Coastguard Worker        if aux_sec_header and aux_sec_header.security_level:
282*cfb92d14SAndroid Build Coastguard Worker            mic, payload_end = self._parse_mic(data, aux_sec_header.security_level)
283*cfb92d14SAndroid Build Coastguard Worker        else:
284*cfb92d14SAndroid Build Coastguard Worker            payload_end = fcs_start
285*cfb92d14SAndroid Build Coastguard Worker            mic = None
286*cfb92d14SAndroid Build Coastguard Worker
287*cfb92d14SAndroid Build Coastguard Worker        # There may be no termination IE. In such case, there is no payload, get
288*cfb92d14SAndroid Build Coastguard Worker        # IE until the beginning position of MIC or a termination IE.
289*cfb92d14SAndroid Build Coastguard Worker        header_ie_list = []
290*cfb92d14SAndroid Build Coastguard Worker        data.seek(cur_pos)
291*cfb92d14SAndroid Build Coastguard Worker        while ie_present and cur_pos + 2 < payload_end:
292*cfb92d14SAndroid Build Coastguard Worker            header_ie = struct.unpack("<H", data.read(2))[0]
293*cfb92d14SAndroid Build Coastguard Worker            id = (header_ie & MacFrame.IEEE802154_HEADER_IE_ID_MASK) >> 7
294*cfb92d14SAndroid Build Coastguard Worker            # Currently, payload IE doesn't exist in the code. So only HT2 is required.
295*cfb92d14SAndroid Build Coastguard Worker            # TODO: support HT1 when there are Payload IEs in our code
296*cfb92d14SAndroid Build Coastguard Worker            assert id != MacFrame.IEEE802154_HEADER_IE_HT1, \
297*cfb92d14SAndroid Build Coastguard Worker                'Currently there should be no HT1!'
298*cfb92d14SAndroid Build Coastguard Worker            header_ie_length = (header_ie & MacFrame.IEEE802154_HEADER_IE_LENGTH_MASK)
299*cfb92d14SAndroid Build Coastguard Worker            assert cur_pos + 2 + header_ie_length <= payload_end, \
300*cfb92d14SAndroid Build Coastguard Worker                'Parsing Header IE error, IE id:{} length:{}'.format(id, header_ie_length)
301*cfb92d14SAndroid Build Coastguard Worker            header_ie_content = data.read(header_ie_length)
302*cfb92d14SAndroid Build Coastguard Worker            header_ie_list.append(InformationElement(id, header_ie_length, header_ie_content))
303*cfb92d14SAndroid Build Coastguard Worker            cur_pos += 2 + header_ie_length
304*cfb92d14SAndroid Build Coastguard Worker            if id == MacFrame.IEEE802154_HEADER_IE_HT2:
305*cfb92d14SAndroid Build Coastguard Worker                break
306*cfb92d14SAndroid Build Coastguard Worker        header_ie_end = cur_pos
307*cfb92d14SAndroid Build Coastguard Worker
308*cfb92d14SAndroid Build Coastguard Worker        payload_pos = cur_pos
309*cfb92d14SAndroid Build Coastguard Worker        payload_len = payload_end - payload_pos
310*cfb92d14SAndroid Build Coastguard Worker        data.seek(payload_pos)
311*cfb92d14SAndroid Build Coastguard Worker        payload = data.read(payload_len)
312*cfb92d14SAndroid Build Coastguard Worker
313*cfb92d14SAndroid Build Coastguard Worker        if security_enabled:
314*cfb92d14SAndroid Build Coastguard Worker            mhr_len = mhr_end - mhr_start
315*cfb92d14SAndroid Build Coastguard Worker            data.seek(mhr_start)
316*cfb92d14SAndroid Build Coastguard Worker            mhr_bytes = data.read(mhr_len)
317*cfb92d14SAndroid Build Coastguard Worker
318*cfb92d14SAndroid Build Coastguard Worker            aux_sec_header_len = aux_sec_header_end - mhr_end
319*cfb92d14SAndroid Build Coastguard Worker            aux_sec_hdr_bytes = data.read(aux_sec_header_len)
320*cfb92d14SAndroid Build Coastguard Worker
321*cfb92d14SAndroid Build Coastguard Worker            extra_open_fields = bytearray([])
322*cfb92d14SAndroid Build Coastguard Worker
323*cfb92d14SAndroid Build Coastguard Worker            if ie_present:
324*cfb92d14SAndroid Build Coastguard Worker                data.seek(header_ie_start)
325*cfb92d14SAndroid Build Coastguard Worker                extra_open_fields += data.read(header_ie_end - header_ie_start)
326*cfb92d14SAndroid Build Coastguard Worker
327*cfb92d14SAndroid Build Coastguard Worker            message_info = MessageInfo()
328*cfb92d14SAndroid Build Coastguard Worker            message_info.aux_sec_hdr = aux_sec_header
329*cfb92d14SAndroid Build Coastguard Worker            message_info.aux_sec_hdr_bytes = aux_sec_hdr_bytes
330*cfb92d14SAndroid Build Coastguard Worker            message_info.extra_open_fields = extra_open_fields
331*cfb92d14SAndroid Build Coastguard Worker            message_info.mhr_bytes = mhr_bytes
332*cfb92d14SAndroid Build Coastguard Worker
333*cfb92d14SAndroid Build Coastguard Worker            open_payload = []
334*cfb92d14SAndroid Build Coastguard Worker            private_payload = payload
335*cfb92d14SAndroid Build Coastguard Worker
336*cfb92d14SAndroid Build Coastguard Worker            # Check end of MAC frame
337*cfb92d14SAndroid Build Coastguard Worker            if frame_type == MacHeader.FrameType.COMMAND:
338*cfb92d14SAndroid Build Coastguard Worker                if frame_version < MacFrame.IEEE802154_VERSION_2015:
339*cfb92d14SAndroid Build Coastguard Worker                    extra_open_fields.append(payload[0])
340*cfb92d14SAndroid Build Coastguard Worker                    open_payload = payload[0:1]
341*cfb92d14SAndroid Build Coastguard Worker                    private_payload = payload[1:]
342*cfb92d14SAndroid Build Coastguard Worker                    message_info.open_payload_length = 1
343*cfb92d14SAndroid Build Coastguard Worker
344*cfb92d14SAndroid Build Coastguard Worker            if src_address.type == MacAddressType.SHORT:
345*cfb92d14SAndroid Build Coastguard Worker                message_info.source_mac_address = DeviceDescriptors.get_extended(src_address).mac_address
346*cfb92d14SAndroid Build Coastguard Worker            else:
347*cfb92d14SAndroid Build Coastguard Worker                message_info.source_mac_address = src_address.mac_address
348*cfb92d14SAndroid Build Coastguard Worker
349*cfb92d14SAndroid Build Coastguard Worker            sec_obj = CryptoEngine(MacCryptoMaterialCreator(config.DEFAULT_NETWORK_KEY))
350*cfb92d14SAndroid Build Coastguard Worker            self.payload = MacPayload(bytearray(open_payload) + sec_obj.decrypt(private_payload, mic, message_info))
351*cfb92d14SAndroid Build Coastguard Worker
352*cfb92d14SAndroid Build Coastguard Worker        else:
353*cfb92d14SAndroid Build Coastguard Worker            self.payload = MacPayload(payload)
354*cfb92d14SAndroid Build Coastguard Worker
355*cfb92d14SAndroid Build Coastguard Worker        if frame_type == MacHeader.FrameType.COMMAND:
356*cfb92d14SAndroid Build Coastguard Worker            command_type = self.payload.data[0]
357*cfb92d14SAndroid Build Coastguard Worker        else:
358*cfb92d14SAndroid Build Coastguard Worker            command_type = None
359*cfb92d14SAndroid Build Coastguard Worker
360*cfb92d14SAndroid Build Coastguard Worker        # Create Header object
361*cfb92d14SAndroid Build Coastguard Worker        self.header = MacHeader(
362*cfb92d14SAndroid Build Coastguard Worker            frame_type,
363*cfb92d14SAndroid Build Coastguard Worker            frame_pending,
364*cfb92d14SAndroid Build Coastguard Worker            ack_request,
365*cfb92d14SAndroid Build Coastguard Worker            frame_version,
366*cfb92d14SAndroid Build Coastguard Worker            seq,
367*cfb92d14SAndroid Build Coastguard Worker            dest_pan_id,
368*cfb92d14SAndroid Build Coastguard Worker            dest_address,
369*cfb92d14SAndroid Build Coastguard Worker            src_pan_id,
370*cfb92d14SAndroid Build Coastguard Worker            src_address,
371*cfb92d14SAndroid Build Coastguard Worker            command_type,
372*cfb92d14SAndroid Build Coastguard Worker            aux_sec_header,
373*cfb92d14SAndroid Build Coastguard Worker            mic,
374*cfb92d14SAndroid Build Coastguard Worker            fcs,
375*cfb92d14SAndroid Build Coastguard Worker        )
376*cfb92d14SAndroid Build Coastguard Worker
377*cfb92d14SAndroid Build Coastguard Worker    def _parse_address(self, data, mode):
378*cfb92d14SAndroid Build Coastguard Worker        if mode == MacHeader.AddressMode.SHORT:
379*cfb92d14SAndroid Build Coastguard Worker            return MacAddress(data.read(2), MacAddressType.SHORT, big_endian=False)
380*cfb92d14SAndroid Build Coastguard Worker
381*cfb92d14SAndroid Build Coastguard Worker        if mode == MacHeader.AddressMode.EXTENDED:
382*cfb92d14SAndroid Build Coastguard Worker            return MacAddress(data.read(8), MacAddressType.LONG, big_endian=False)
383*cfb92d14SAndroid Build Coastguard Worker
384*cfb92d14SAndroid Build Coastguard Worker        else:
385*cfb92d14SAndroid Build Coastguard Worker            return None
386*cfb92d14SAndroid Build Coastguard Worker
387*cfb92d14SAndroid Build Coastguard Worker    def _parse_aux_sec_header(self, data):
388*cfb92d14SAndroid Build Coastguard Worker        security_control, frame_counter = struct.unpack("<BL", data.read(5))
389*cfb92d14SAndroid Build Coastguard Worker
390*cfb92d14SAndroid Build Coastguard Worker        security_level = security_control & 0x07
391*cfb92d14SAndroid Build Coastguard Worker        key_id_mode = (security_control & 0x18) >> 3
392*cfb92d14SAndroid Build Coastguard Worker
393*cfb92d14SAndroid Build Coastguard Worker        if key_id_mode == 0:
394*cfb92d14SAndroid Build Coastguard Worker            raise KeyIdMode0Exception
395*cfb92d14SAndroid Build Coastguard Worker        elif key_id_mode == 1:
396*cfb92d14SAndroid Build Coastguard Worker            key_id = data.read(1)
397*cfb92d14SAndroid Build Coastguard Worker        elif key_id_mode == 2:
398*cfb92d14SAndroid Build Coastguard Worker            key_id = data.read(5)
399*cfb92d14SAndroid Build Coastguard Worker        elif key_id_mode == 3:
400*cfb92d14SAndroid Build Coastguard Worker            key_id = data.read(9)
401*cfb92d14SAndroid Build Coastguard Worker        else:
402*cfb92d14SAndroid Build Coastguard Worker            pass
403*cfb92d14SAndroid Build Coastguard Worker
404*cfb92d14SAndroid Build Coastguard Worker        return AuxiliarySecurityHeader(
405*cfb92d14SAndroid Build Coastguard Worker            key_id_mode,
406*cfb92d14SAndroid Build Coastguard Worker            security_level,
407*cfb92d14SAndroid Build Coastguard Worker            frame_counter,
408*cfb92d14SAndroid Build Coastguard Worker            key_id,
409*cfb92d14SAndroid Build Coastguard Worker            big_endian=False,
410*cfb92d14SAndroid Build Coastguard Worker        )
411*cfb92d14SAndroid Build Coastguard Worker
412*cfb92d14SAndroid Build Coastguard Worker    def _parse_mic(self, data, security_level):
413*cfb92d14SAndroid Build Coastguard Worker        if security_level in (1, 5):
414*cfb92d14SAndroid Build Coastguard Worker            data.seek(-4, io.SEEK_CUR)
415*cfb92d14SAndroid Build Coastguard Worker            payload_end = data.tell()
416*cfb92d14SAndroid Build Coastguard Worker            mic = data.read(4)
417*cfb92d14SAndroid Build Coastguard Worker        elif security_level in (2, 6):
418*cfb92d14SAndroid Build Coastguard Worker            data.seek(-8, io.SEEK_CUR)
419*cfb92d14SAndroid Build Coastguard Worker            payload_end = data.tell()
420*cfb92d14SAndroid Build Coastguard Worker            mic = data.read(8)
421*cfb92d14SAndroid Build Coastguard Worker        elif security_level in (3, 7):
422*cfb92d14SAndroid Build Coastguard Worker            data.seek(-16, io.SEEK_CUR)
423*cfb92d14SAndroid Build Coastguard Worker            payload_end = data.tell()
424*cfb92d14SAndroid Build Coastguard Worker            mic = data.read(16)
425*cfb92d14SAndroid Build Coastguard Worker        else:
426*cfb92d14SAndroid Build Coastguard Worker            payload_end = data.tell()
427*cfb92d14SAndroid Build Coastguard Worker
428*cfb92d14SAndroid Build Coastguard Worker        return mic, payload_end
429*cfb92d14SAndroid Build Coastguard Worker
430*cfb92d14SAndroid Build Coastguard Worker    def _parse_fcs(self, data, fcs_start):
431*cfb92d14SAndroid Build Coastguard Worker        data.seek(fcs_start)
432*cfb92d14SAndroid Build Coastguard Worker        fcs = bytearray(data.read(2))
433*cfb92d14SAndroid Build Coastguard Worker        return fcs
434