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