コード例 #1
0
    def parse(self, data):
        mhr_start = data.tell()

        fc, seq = struct.unpack("<HB", data.read(3))

        frame_type = fc & 0x0007
        security_enabled = bool(fc & 0x0008)
        frame_pending = bool(fc & 0x0010)
        ack_request = bool(fc & 0x0020)
        panid_compression = bool(fc & 0x0040)
        dest_addr_mode = (fc & 0x0c00) >> 10
        frame_version = (fc & 0x3000) >> 12
        source_addr_mode = (fc & 0xc000) >> 14

        if frame_type == MacHeader.FrameType.ACK:
            fcs = self._parse_fcs(data, data.tell())
            self.header = MacHeader(frame_type,
                                    frame_pending,
                                    ack_request,
                                    frame_version,
                                    seq,
                                    fcs=fcs)
            self.payload = None
            return

        # Presence of PAN Ids is not fully implemented yet but should be enough for Thread.
        dest_pan_id = struct.unpack("<H", data.read(2))[0]

        dest_address = self._parse_address(data, dest_addr_mode)

        if not panid_compression:
            src_pan_id = struct.unpack("<H", data.read(2))[0]
        else:
            src_pan_id = dest_pan_id

        src_address = self._parse_address(data, source_addr_mode)

        mhr_end = data.tell()

        if security_enabled:
            aux_sec_header = self._parse_aux_sec_header(data)
            aux_sec_header_end = data.tell()
        else:
            aux_sec_header = None

        # Check end of MAC frame
        if frame_type == MacHeader.FrameType.COMMAND:
            command_type = ord(data.read(1))
        else:
            command_type = None

        payload_pos = data.tell()

        data.seek(-2, io.SEEK_END)
        fcs_start = data.tell()

        if aux_sec_header and aux_sec_header.security_level:
            mic, payload_end = self._parse_mic(data,
                                               aux_sec_header.security_level)
        else:
            payload_end = data.tell()
            mic = None

        fcs = self._parse_fcs(data, fcs_start)

        # Create Header object
        self.header = MacHeader(frame_type, frame_pending, ack_request,
                                frame_version, seq, dest_pan_id, dest_address,
                                src_pan_id, src_address, command_type,
                                aux_sec_header, mic, fcs)

        # Create Payload object
        payload_len = payload_end - payload_pos
        data.seek(payload_pos)

        payload = data.read(payload_len)

        if security_enabled:
            mhr_len = mhr_end - mhr_start
            data.seek(mhr_start)
            mhr_bytes = data.read(mhr_len)

            aux_sec_header_len = aux_sec_header_end - mhr_end
            aux_sec_hdr_bytes = data.read(aux_sec_header_len)

            non_payload_fields = bytearray([])

            if command_type is not None:
                non_payload_fields.append(command_type)

            message_info = MessageInfo()
            message_info.aux_sec_hdr = aux_sec_header
            message_info.aux_sec_hdr_bytes = aux_sec_hdr_bytes
            message_info.nonpayload_fields = non_payload_fields
            message_info.mhr_bytes = mhr_bytes
            if src_address.type == MacAddressType.SHORT:
                message_info.source_mac_address = DeviceDescriptors.get_extended(
                    src_address).mac_address
            else:
                message_info.source_mac_address = src_address.mac_address

            sec_obj = CryptoEngine(
                MacCryptoMaterialCreator(config.DEFAULT_MASTER_KEY))
            self.payload = MacPayload(
                sec_obj.decrypt(payload, mic, message_info))

        else:
            self.payload = MacPayload(payload)
コード例 #2
0
ファイル: mac802154.py プロジェクト: zhanglongxia/openthread
    def parse(self, data):
        """Parse a MAC 802.15.4 frame

        Format of MAC 802.15.4 Frame:
        | Frame Header | ASH | IE | Frame Payload | MIC | FCS |

        Frame Header:  Frame Control | Sequence Number | Addressing Field
        ASH: Auxiliary Security Header (optional)
        IE: Header IE | Payload IE (optional)
        Frame Payload: Data payload (optional)
        MIC: To authenticate the frame (optional)

        In the parsing process, Frame Header is parsed first. Then it can be
        determined if security is enabled for this frame. If it's enabled,
        then ASH should be parsed.
        After that, go directly to the end to parse FCS first instead
        of parsing IE or Frame Payload. This is because sometimes, IE doesn't
        have a termination IE and parsing needs to know the start of MIC to determine
        where's the end of IEs(In such cases there are no payload).
        After parsing FCS, MIC is parsed if security is enabled.
        Then the end of IE(or payload) is known. And at last IEs and payload
        are parsed.
        And after parsing everything, build MacHeader and MacPayload with
        the things parsed.
        """
        mhr_start = data.tell()

        fc, seq = struct.unpack("<HB", data.read(3))

        frame_type = fc & 0x0007
        security_enabled = bool(fc & 0x0008)
        frame_pending = bool(fc & 0x0010)
        ack_request = bool(fc & 0x0020)
        panid_compression = bool(fc & 0x0040)
        dest_addr_mode = (fc & 0x0C00) >> 10
        frame_version = (fc & 0x3000) >> 12
        source_addr_mode = (fc & 0xC000) >> 14
        ie_present = bool(fc & 0x0200)

        if frame_type == MacHeader.FrameType.ACK:
            fcs = self._parse_fcs(data, data.tell())
            self.header = MacHeader(
                frame_type,
                frame_pending,
                ack_request,
                frame_version,
                seq,
                fcs=fcs,
            )
            self.payload = None
            return

        dest_addr_present = dest_addr_mode != MacHeader.AddressMode.NOT_PRESENT
        src_addr_present = source_addr_mode != MacHeader.AddressMode.NOT_PRESENT

        if frame_version < 2:
            dest_pan_present = dest_addr_present
        else:
            dest_pan_present = True
            if not src_addr_present:
                dest_pan_present = src_pan_present != panid_compression
            elif not dest_addr_present:
                dest_pan_present = False
            else:
                if dest_addr_mode == MacHeader.AddressMode.EXTENDED and source_addr_mode == MacHeader.AddressMode.EXTENDED and panid_compression:
                    dest_pan_present = False

        if dest_pan_present:
            dest_pan_id = struct.unpack("<H", data.read(2))[0]
        else:
            dest_pan_id = None

        dest_address = self._parse_address(data, dest_addr_mode)

        src_pan_present = not panid_compression
        while src_pan_present:
            if frame_version < 2:
                break
            if frame_version == 3:
                assert False
            if dest_addr_mode == 0:
                break
            if dest_addr_mode == 2:
                break
            if dest_addr_mode == 3 and source_addr_mode == 2:
                break
            src_pan_present = False

        if src_pan_present:
            src_pan_id = struct.unpack("<H", data.read(2))[0]
        else:
            src_pan_id = dest_pan_id

        src_address = self._parse_address(data, source_addr_mode)

        mhr_end = data.tell()

        if security_enabled:
            aux_sec_header = self._parse_aux_sec_header(data)
            aux_sec_header_end = data.tell()
        else:
            aux_sec_header = None

        # Record the beginning position of header IE.
        # Or the position of payload if there is no header IE.
        cur_pos = data.tell()
        header_ie_start = cur_pos

        data.seek(-2, io.SEEK_END)
        fcs_start = data.tell()
        fcs = self._parse_fcs(data, fcs_start)

        data.seek(fcs_start)
        if aux_sec_header and aux_sec_header.security_level:
            mic, payload_end = self._parse_mic(data,
                                               aux_sec_header.security_level)
        else:
            payload_end = fcs_start
            mic = None

        # There may be no termination IE. In such case, there is no payload, get
        # IE until the beginning position of MIC or a termination IE.
        header_ie_list = []
        data.seek(cur_pos)
        while ie_present and cur_pos + 2 < payload_end:
            header_ie = struct.unpack("<H", data.read(2))[0]
            id = (header_ie & MacFrame.IEEE802154_HEADER_IE_ID_MASK) >> 7
            # Currently, payload IE doesn't exist in the code. So only HT2 is required.
            # TODO: support HT1 when there are Payload IEs in our code
            assert id != MacFrame.IEEE802154_HEADER_IE_HT1, \
                'Currently there should be no HT1!'
            header_ie_length = (header_ie
                                & MacFrame.IEEE802154_HEADER_IE_LENGTH_MASK)
            assert cur_pos + 2 + header_ie_length <= payload_end, \
                'Parsing Header IE error, IE id:{} length:{}'.format(id, header_ie_length)
            header_ie_content = data.read(header_ie_length)
            header_ie_list.append(
                InformationElement(id, header_ie_length, header_ie_content))
            cur_pos += 2 + header_ie_length
            if id == MacFrame.IEEE802154_HEADER_IE_HT2:
                break
        header_ie_end = cur_pos

        payload_pos = cur_pos
        payload_len = payload_end - payload_pos
        data.seek(payload_pos)
        payload = data.read(payload_len)

        if security_enabled:
            mhr_len = mhr_end - mhr_start
            data.seek(mhr_start)
            mhr_bytes = data.read(mhr_len)

            aux_sec_header_len = aux_sec_header_end - mhr_end
            aux_sec_hdr_bytes = data.read(aux_sec_header_len)

            extra_open_fields = bytearray([])

            if ie_present:
                data.seek(header_ie_start)
                extra_open_fields += data.read(header_ie_end - header_ie_start)

            message_info = MessageInfo()
            message_info.aux_sec_hdr = aux_sec_header
            message_info.aux_sec_hdr_bytes = aux_sec_hdr_bytes
            message_info.extra_open_fields = extra_open_fields
            message_info.mhr_bytes = mhr_bytes

            open_payload = []
            private_payload = payload

            # Check end of MAC frame
            if frame_type == MacHeader.FrameType.COMMAND:
                if frame_version < MacFrame.IEEE802154_VERSION_2015:
                    extra_open_fields.append(payload[0])
                    open_payload = payload[0:1]
                    private_payload = payload[1:]
                    message_info.open_payload_length = 1

            if src_address.type == MacAddressType.SHORT:
                message_info.source_mac_address = DeviceDescriptors.get_extended(
                    src_address).mac_address
            else:
                message_info.source_mac_address = src_address.mac_address

            sec_obj = CryptoEngine(
                MacCryptoMaterialCreator(config.DEFAULT_NETWORK_KEY))
            self.payload = MacPayload(
                bytearray(open_payload) +
                sec_obj.decrypt(private_payload, mic, message_info))

        else:
            self.payload = MacPayload(payload)

        if frame_type == MacHeader.FrameType.COMMAND:
            command_type = self.payload.data[0]
        else:
            command_type = None

        # Create Header object
        self.header = MacHeader(
            frame_type,
            frame_pending,
            ack_request,
            frame_version,
            seq,
            dest_pan_id,
            dest_address,
            src_pan_id,
            src_address,
            command_type,
            aux_sec_header,
            mic,
            fcs,
        )