r'''
        Parse the given packet and update properties accordingly

        >>> data_hex = ('c033d3c10000000745c0005835400000'
        ...             'ff06094a254d38204d45d1a30016f597'
        ...             'a1c3c7406718bf1b50180ff0793f0000'
        ...             'b555e59ff5ba6aad33d875c600fd8c1f'
        ...             'c5268078f365ee199179fbd09d09d690'
        ...             '193622a6b70bcbc7bf5f20dda4258801')
        >>> data = data_hex.decode('hex')
        >>> message = DataPacket.from_bytes(data)
        >>> message.echo_nonce_request
        False
        >>> message.nonce
        '3\xd3\xc1'
        >>> message.source_map_version
        >>> message.destination_map_version
        >>> message.lsb
        ... # doctest: +ELLIPSIS
        [True, True, True, False, False, ..., False, False, False, False]
        >>> message.instance_id
        >>> bytes(message.payload)
        ... # doctest: +ELLIPSIS
        'E\xc0\x00X5@\x00\x00\xff\x06\tJ%M8...\xdd\xa4%\x88\x01'

def from_bytes(cls, bitstream, decode_payload=True):
        r'''
        Parse the given packet and update properties accordingly

        >>> data_hex = ('c033d3c10000000745c0005835400000'
        ...             'ff06094a254d38204d45d1a30016f597'
        ...             'a1c3c7406718bf1b50180ff0793f0000'
        ...             'b555e59ff5ba6aad33d875c600fd8c1f'
        ...             'c5268078f365ee199179fbd09d09d690'
        ...             '193622a6b70bcbc7bf5f20dda4258801')
        >>> data = data_hex.decode('hex')
        >>> message = DataPacket.from_bytes(data)
        >>> message.echo_nonce_request
        False
        >>> message.nonce
        '3\xd3\xc1'
        >>> message.source_map_version
        >>> message.destination_map_version
        >>> message.lsb
        ... # doctest: +ELLIPSIS
        [True, True, True, False, False, ..., False, False, False, False]
        >>> message.instance_id
        >>> bytes(message.payload)
        ... # doctest: +ELLIPSIS
        'E\xc0\x00X5@\x00\x00\xff\x06\tJ%M8...\xdd\xa4%\x88\x01'
        '''
        packet = cls()

        # Convert to ConstBitStream (if not already provided)
        if not isinstance(bitstream, ConstBitStream):
            if isinstance(bitstream, Bits):
                bitstream = ConstBitStream(auto=bitstream)
            else:
                bitstream = ConstBitStream(bytes=bitstream)

        # Read the flags
        (nonce_present,
         lsb_enabled,
         packet.echo_nonce_request,
         map_version_present,
         instance_id_present) = bitstream.readlist('5*bool')

        # Skip over reserved bits
        bitstream.read(3)

        # Parse nonce or map versions
        if nonce_present:
            # Nonce: yes, versions: no
            packet.nonce = bitstream.read('bytes:3')
            packet.source_map_version = None
            packet.destination_map_version = None
        elif map_version_present:
            # Nonce: no, versions: yes
            packet.nonce = None
            (packet.source_map_version,
             packet.destination_map_version) = bitstream.readlist('2*uint:12')
        else:
            # Nonce: no, versions: no
            packet.nonce = None
            packet.source_map_version = None
            packet.destination_map_version = None

            # Skip over the nonce/map-version bits
            bitstream.read(24)

        # Parse instance-id
        if instance_id_present:
            packet.instance_id = bitstream.read('uint:24')

            # 8 bits remaining for LSB
            lsb_bits = 8
        else:
            # 32 bits remaining for LSB
            lsb_bits = 32

        # Parse LSBs
        if lsb_enabled:
            packet.lsb = bitstream.readlist('%d*bool' % lsb_bits)

            # Reverse for readability: least significant locator-bit first
            packet.lsb.reverse()
        else:
            # Skip over the LSBs
            bitstream.read(lsb_bits)

        # The rest of the packet is payload
        remaining = bitstream[bitstream.pos:]

        # Parse IP packet
        if len(remaining):
            ip_version = remaining.peek('uint:4')
            if ip_version == 4:
                packet.payload = IPv4Packet.from_bytes(remaining, decode_payload=decode_payload)
            elif ip_version == 6:
                packet.payload = IPv6Packet.from_bytes(remaining, decode_payload=decode_payload)
            else:
                packet.payload = remaining.bytes

        # Verify that the properties make sense
        packet.sanitize()

        return packet