xref: /aosp_15_r20/external/openthread/tests/scripts/thread-cert/wpan.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cfb92d14SAndroid Build Coastguard Worker#
3*cfb92d14SAndroid Build Coastguard Worker#  Copyright (c) 2020, 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 struct
31*cfb92d14SAndroid Build Coastguard Worker
32*cfb92d14SAndroid Build Coastguard Workerfrom collections import namedtuple
33*cfb92d14SAndroid Build Coastguard Workerfrom enum import Enum
34*cfb92d14SAndroid Build Coastguard Worker
35*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_BEACON = 0 << 0
36*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_DATA = 1 << 0
37*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_ACK = 2 << 0
38*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_MAC_CMD = 3 << 0
39*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_TYPE_MASK = 7 << 0
40*cfb92d14SAndroid Build Coastguard WorkerFCF_SECURITY_ENABLED = 1 << 3
41*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_PENDING = 1 << 4
42*cfb92d14SAndroid Build Coastguard WorkerFCF_ACK_REQUEST = 1 << 5
43*cfb92d14SAndroid Build Coastguard WorkerFCF_PANID_COMPRESSION = 1 << 6
44*cfb92d14SAndroid Build Coastguard WorkerFCF_IE_PRESENT = 1 << 9
45*cfb92d14SAndroid Build Coastguard WorkerFCF_DST_ADDR_NONE = 0 << 10
46*cfb92d14SAndroid Build Coastguard WorkerFCF_DST_ADDR_SHORT = 2 << 10
47*cfb92d14SAndroid Build Coastguard WorkerFCF_DST_ADDR_EXT = 3 << 10
48*cfb92d14SAndroid Build Coastguard WorkerFCF_DST_ADDR_MASK = 3 << 10
49*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_VERSION_2006 = 1 << 12
50*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_VERSION_2015 = 2 << 12
51*cfb92d14SAndroid Build Coastguard WorkerFCF_FRAME_VERSION_MASK = 3 << 12
52*cfb92d14SAndroid Build Coastguard WorkerFCF_SRC_ADDR_NONE = 0 << 14
53*cfb92d14SAndroid Build Coastguard WorkerFCF_SRC_ADDR_SHORT = 2 << 14
54*cfb92d14SAndroid Build Coastguard WorkerFCF_SRC_ADDR_EXT = 3 << 14
55*cfb92d14SAndroid Build Coastguard WorkerFCD_SRC_ADDR_MASK = 3 << 14
56*cfb92d14SAndroid Build Coastguard Worker
57*cfb92d14SAndroid Build Coastguard Worker
58*cfb92d14SAndroid Build Coastguard Workerclass DstAddrMode(Enum):
59*cfb92d14SAndroid Build Coastguard Worker    NONE = 0
60*cfb92d14SAndroid Build Coastguard Worker    RESERVED = 1
61*cfb92d14SAndroid Build Coastguard Worker    SHORT = 2
62*cfb92d14SAndroid Build Coastguard Worker    EXTENDED = 3
63*cfb92d14SAndroid Build Coastguard Worker
64*cfb92d14SAndroid Build Coastguard Worker
65*cfb92d14SAndroid Build Coastguard Workerclass FrameType(Enum):
66*cfb92d14SAndroid Build Coastguard Worker    BEACON = 0
67*cfb92d14SAndroid Build Coastguard Worker    DATA = 1
68*cfb92d14SAndroid Build Coastguard Worker    ACK = 2
69*cfb92d14SAndroid Build Coastguard Worker    COMMAND = 3
70*cfb92d14SAndroid Build Coastguard Worker
71*cfb92d14SAndroid Build Coastguard Worker
72*cfb92d14SAndroid Build Coastguard Workerclass WpanFrameInfo(namedtuple('WpanFrameInfo', ['fcf', 'seq_no', 'dst_extaddr', 'dst_short'])):
73*cfb92d14SAndroid Build Coastguard Worker
74*cfb92d14SAndroid Build Coastguard Worker    @property
75*cfb92d14SAndroid Build Coastguard Worker    def frame_type(self) -> FrameType:
76*cfb92d14SAndroid Build Coastguard Worker        return FrameType(self.fcf & 0x7)
77*cfb92d14SAndroid Build Coastguard Worker
78*cfb92d14SAndroid Build Coastguard Worker    @property
79*cfb92d14SAndroid Build Coastguard Worker    def dst_addr_mode(self) -> DstAddrMode:
80*cfb92d14SAndroid Build Coastguard Worker        return DstAddrMode((self.fcf & 0x0c00) >> 10)
81*cfb92d14SAndroid Build Coastguard Worker
82*cfb92d14SAndroid Build Coastguard Worker    @property
83*cfb92d14SAndroid Build Coastguard Worker    def is_broadcast(self) -> bool:
84*cfb92d14SAndroid Build Coastguard Worker        return self.dst_addr_mode == DstAddrMode.SHORT and self.dst_short == 0xffff
85*cfb92d14SAndroid Build Coastguard Worker
86*cfb92d14SAndroid Build Coastguard Worker
87*cfb92d14SAndroid Build Coastguard Workerdef _is_version_2015(fcf: int) -> bool:
88*cfb92d14SAndroid Build Coastguard Worker    return (fcf & FCF_FRAME_VERSION_MASK) == FCF_FRAME_VERSION_2015
89*cfb92d14SAndroid Build Coastguard Worker
90*cfb92d14SAndroid Build Coastguard Worker
91*cfb92d14SAndroid Build Coastguard Workerdef _is_dst_addr_present(fcf: int) -> bool:
92*cfb92d14SAndroid Build Coastguard Worker    dst_addr_mode = DstAddrMode((fcf & 0x0c00) >> 10)
93*cfb92d14SAndroid Build Coastguard Worker    return dst_addr_mode != DstAddrMode.NONE
94*cfb92d14SAndroid Build Coastguard Worker
95*cfb92d14SAndroid Build Coastguard Worker
96*cfb92d14SAndroid Build Coastguard Worker_DST_PAN_ID_NOT_PRESENT_SET = {
97*cfb92d14SAndroid Build Coastguard Worker    FCF_DST_ADDR_NONE | FCF_SRC_ADDR_NONE,
98*cfb92d14SAndroid Build Coastguard Worker    FCF_DST_ADDR_EXT | FCF_SRC_ADDR_NONE | FCF_PANID_COMPRESSION,
99*cfb92d14SAndroid Build Coastguard Worker    FCF_DST_ADDR_SHORT | FCF_SRC_ADDR_NONE | FCF_PANID_COMPRESSION,
100*cfb92d14SAndroid Build Coastguard Worker    FCF_DST_ADDR_NONE | FCF_SRC_ADDR_EXT,
101*cfb92d14SAndroid Build Coastguard Worker    FCF_DST_ADDR_NONE | FCF_SRC_ADDR_SHORT,
102*cfb92d14SAndroid Build Coastguard Worker    FCF_DST_ADDR_NONE | FCF_SRC_ADDR_EXT | FCF_PANID_COMPRESSION,
103*cfb92d14SAndroid Build Coastguard Worker    FCF_DST_ADDR_NONE | FCF_SRC_ADDR_SHORT | FCF_PANID_COMPRESSION,
104*cfb92d14SAndroid Build Coastguard Worker    FCF_DST_ADDR_EXT | FCF_SRC_ADDR_EXT | FCF_PANID_COMPRESSION,
105*cfb92d14SAndroid Build Coastguard Worker}
106*cfb92d14SAndroid Build Coastguard Worker
107*cfb92d14SAndroid Build Coastguard Worker
108*cfb92d14SAndroid Build Coastguard Workerdef _is_dst_pan_id_present(fcf: int) -> bool:
109*cfb92d14SAndroid Build Coastguard Worker    if _is_version_2015(fcf):
110*cfb92d14SAndroid Build Coastguard Worker        v = fcf & (FCF_DST_ADDR_MASK | FCD_SRC_ADDR_MASK | FCF_PANID_COMPRESSION)
111*cfb92d14SAndroid Build Coastguard Worker        present = v not in _DST_PAN_ID_NOT_PRESENT_SET
112*cfb92d14SAndroid Build Coastguard Worker    else:
113*cfb92d14SAndroid Build Coastguard Worker        present = _is_dst_addr_present(fcf)
114*cfb92d14SAndroid Build Coastguard Worker
115*cfb92d14SAndroid Build Coastguard Worker    return present
116*cfb92d14SAndroid Build Coastguard Worker
117*cfb92d14SAndroid Build Coastguard Worker
118*cfb92d14SAndroid Build Coastguard Workerdef dissect(frame: bytes) -> WpanFrameInfo:
119*cfb92d14SAndroid Build Coastguard Worker    fcf = struct.unpack("<H", frame[1:3])[0]
120*cfb92d14SAndroid Build Coastguard Worker
121*cfb92d14SAndroid Build Coastguard Worker    seq_no = frame[3]
122*cfb92d14SAndroid Build Coastguard Worker
123*cfb92d14SAndroid Build Coastguard Worker    dst_addr_mode = (fcf & 0x0c00) >> 10
124*cfb92d14SAndroid Build Coastguard Worker
125*cfb92d14SAndroid Build Coastguard Worker    dst_extaddr, dst_short = None, None
126*cfb92d14SAndroid Build Coastguard Worker
127*cfb92d14SAndroid Build Coastguard Worker    if dst_addr_mode in [DstAddrMode.SHORT.value, DstAddrMode.EXTENDED.value]:
128*cfb92d14SAndroid Build Coastguard Worker        offset = 4
129*cfb92d14SAndroid Build Coastguard Worker
130*cfb92d14SAndroid Build Coastguard Worker        if _is_dst_pan_id_present(fcf):
131*cfb92d14SAndroid Build Coastguard Worker            offset += 2
132*cfb92d14SAndroid Build Coastguard Worker
133*cfb92d14SAndroid Build Coastguard Worker        if dst_addr_mode == DstAddrMode.SHORT.value:
134*cfb92d14SAndroid Build Coastguard Worker            dst_short = struct.unpack('<H', frame[offset:offset + 2])[0]
135*cfb92d14SAndroid Build Coastguard Worker        else:
136*cfb92d14SAndroid Build Coastguard Worker            dst_extaddr = '%016x' % struct.unpack('<Q', frame[offset:offset + 8])[0]
137*cfb92d14SAndroid Build Coastguard Worker
138*cfb92d14SAndroid Build Coastguard Worker    return WpanFrameInfo(fcf=fcf, seq_no=seq_no, dst_extaddr=dst_extaddr, dst_short=dst_short)
139