class DTLSAlert(TLSDecryptablePacket): """Additional class for scapy support for DTLS.""" name = "DTLS Alert" fields_desc = [ ByteEnumField("level", TLSAlertLevel.WARNING, TLS_ALERT_LEVELS), ByteEnumField("description", TLSAlertDescription.CLOSE_NOTIFY, TLS_ALERT_DESCRIPTIONS), ]
class DTLSServerHello(PacketNoPayload): """Representation of DTLSServerHello message""" name = "DTLS Server Hello" fields_desc = [ XShortEnumField("version", ENUM_DTLS_VERSIONS.DTLS_1_1, DTLS_VERSIONS), IntField("gmt_unix_time", int(time.time())), StrFixedLenField("random_bytes", os.urandom(28), 28), XFieldLenField("session_id_length", None, length_of="session_id", fmt="B"), StrLenField( "session_id", os.urandom(20), length_from=lambda x: x.session_id_length ), XShortEnumField( "cipher_suite", TLSCipherSuite.RSA_WITH_AES_128_CBC_SHA, TLS_CIPHER_SUITES ), ByteEnumField( "compression_method", TLSCompressionMethod.NULL, TLS_COMPRESSION_METHODS ), StrConditionalField( XFieldLenField("extensions_length", None, length_of="extensions", fmt="H"), lambda pkt, s, val: True if val or pkt.extensions or (s and struct.unpack("!H", s[:2])[0] == len(s) - 2) else False, ), TypedPacketListField( "extensions", None, TLSExtension, length_from=lambda x: x.extensions_length, type_="DTLSServerHello", ), ]
class ExtendedBroadcastData(Packet): fields_desc = [ XByteField('extended', 0x80), XShortField('device_number', 0), ByteEnumField('device_type', 0, ENUM_DEVICE_TYPE), # ByteField('transmission_type', 0), BitEnumField( 'channel_type', 0, 2, { 0: 'RESERVED', 1: 'INDEPENDENT', 2: 'SHARED 1-BYTE ADDR', 3: 'SHARED 2-BYTE ADDR', }, ), BitEnumField('global_data', 0, 1, { 0: 'NOT USED', 1: 'USED' }), BitField('undefined', 0, 1), BitField('ext_serial_number', 0, 4), ]
class DsToRioUdp(Packet): name = 'DS to RIO UDP Packet' fields_desc = [ ShortField('seq_num', None), ByteField('comm_ver', 0), FlagsField('control', 0, 8, [ 'test', 'auton', 'enabled', 'fms_connected', 'reserved4', 'reserved5', 'reserved6', 'estop' ]), FlagsField('request', 0, 8, [ 'reserved0', 'reserved1', 'restart_code', 'reboot_rio', 'reserved4', 'reserved5', 'reserved6', 'reserved7' ]), ByteEnumField( 'alliance', None, ['red_0', 'red_1', 'red_2', 'blue_0', 'blue_1', 'blue_2']), PacketListField('tags', [], Tag) ]
class OpenFlowHeader(Packet): name = "OpenFlowHeader" """ length should be length of the payload OpenFlowRequest or OpenFlowResponse + 8 for header). I am condensing req and res to a single class OpenFlowMessage """ fields_desc = [ XByteField("version", 0x04), ByteEnumField("type", 0, OF_TYPES), ShortField("length", None), IntField("xid", 676265) ] def post_build(self, curr_layer, payload): if self.length is None: #l = 8 + len(payload) # hardcoded 8 as size of header l = len(curr_layer) + len(payload) curr_layer = curr_layer[:2] + pack("!H", l) + curr_layer[4:] return curr_layer + payload def guess_payload_class(self, payload): if self.type == 0: return OpenFlowHello #if self.type == 1: # return OpenFlowError elif self.type == 2: return OpenFlowEchoRequest elif self.type == 3: return OpenFlowEchoReply #if self.type == 4: # return OpenFlowEchoReply elif self.type == 5: return OpenFlowFeaturesRequest elif self.type == 6: return OpenFlowFeaturesReply else: return Packet.guess_payload_class(self, payload)
class TWAMPTestResponse(Packet): """A packet representing a TWAMP response""" name = "TWAMPResponse" fields_desc = [ IntField("SequenceNumber", 0), LongField("TransmitCounter", 0), BitField("X", 0, 1), BitField("B", 0, 1), BitField("MBZ", 0, 6), XByteField("BlockNumber", 0), ShortField("MBZ", 0), LongField("ReceiveCounter", 0), IntField("SenderSequenceNumber", 0), LongField("SenderCounter", 0), BitField("X2", 0, 1), BitField("B2", 0, 1), BitField("MBZ", 0, 6), XByteField("SenderBlockNumber", 0), XByteField("MBZ", 0), ByteEnumField("ReceverControlCode", 0, {1: "Error - Invalid Message"}), XByteField("SenderTTL", 0) ] # manca il padding
class TWAMPTestQuery(Packet): """A packet representing a TWAMP query""" name = "TWAMPQuery" fields_desc = [ IntField("SequenceNumber", 0), LongField("TransmitCounter", 0), BitEnumField("X", 1, 1, { 0: "32bit Counter", 1: "64bit Counter" }), BitEnumField("B", 0, 1, { 0: "Packet Counter", 1: "Octet Counter" }), BitField("MBZ", 0, 6), ByteField("BlockNumber", 0), ShortField("MBZ", 0), ThreeBytesField("MBZ", 0), ByteEnumField("SenderControlCode", 0, { 0: "Out-of-band Response Requested", 1: "In-band Response Requested" }) ] # manca il padding
class OpenFlowBody_v1_3(Packet): """ OpenFlow Packet v1.3 """ name = 'OpenFlowBody_v1_3' fields_desc = [ # Header ByteEnumField('Type', None, ofp_v1_3_message_type), ShortField('Length', None), IntField('ID', None), # Error message body ConditionalField(ShortField('ErrorType', None), lambda pkt: pkt.Type == 1), ConditionalField(ShortField('ErrorCode', None), lambda pkt: pkt.Type == 1), # Echo Request / Echo Reply message body ConditionalField(StrField('Data', None), lambda pkt: pkt.Type in [1, 2, 3]), # Vendor message body #ConditionalField(IntField('VendorID', None), lambda pkt: pkt.Type == 4), # type ???? # Experimenter ConditionalField(XIntField('ExperimenterID', None), lambda pkt: pkt.Type == 4), ConditionalField(IntField('ExperimenterType', None), lambda pkt: pkt.Type == 4), # Features Reply message body ConditionalField(XLongField('DatapathID', None), lambda pkt: pkt.Type == 6), ConditionalField(IntField('MaxBuffers', None), lambda pkt: pkt.Type == 6), ConditionalField(ByteField('MaxTables', None), lambda pkt: pkt.Type == 6), ConditionalField(ByteField('AuxiliaryID', None), lambda pkt: pkt.Type == 6), ConditionalField(XByteField('FeaturesReplyPad', None), lambda pkt: pkt.Type == 6), ConditionalField(XIntField('Capabilities', None), lambda pkt: pkt.Type == 6), ConditionalField(IntField('FeaturesReplyReserved', None), lambda pkt: pkt.Type == 6), # Set Config message body ConditionalField(XShortField('SwitchConfigurationFlags', None), lambda pkt: pkt.Type == 9), ConditionalField(ShortField('MissSendLength', None), lambda pkt: pkt.Type == 9), # Packet Input Notification message body ConditionalField( IntField('PacketInputNotificationPacketBufferID', None), lambda pkt: pkt.Type == 10), ConditionalField(ShortField('EthernetFrameLength', None), lambda pkt: pkt.Type == 10), ConditionalField(ByteField('PacketInputNotificationReason', None), lambda pkt: pkt.Type == 10), ConditionalField(ByteField('PacketInputNotificationTableID', None), lambda pkt: pkt.Type == 10), ConditionalField(XLongField('PacketInputNotificationCookie', None), lambda pkt: pkt.Type == 10), # Flow Removed Notification message body ConditionalField(XLongField('FlowRemovedNotificationCookie', None), lambda pkt: pkt.Type == 11), ConditionalField(ShortField('FlowRemovedNotificationPriority', None), lambda pkt: pkt.Type == 11), ConditionalField(ByteField('FlowRemovedNotificationReason', None), lambda pkt: pkt.Type == 11), ConditionalField(ByteField('FlowRemovedNotificationTableID', None), lambda pkt: pkt.Type == 11), ConditionalField(IntField('Duration_sec', None), lambda pkt: pkt.Type == 11), ConditionalField(IntField('Duration_nsec', None), lambda pkt: pkt.Type == 11), ConditionalField( ShortField('FlowRemovedNotificationIdleTimeout', None), lambda pkt: pkt.Type == 11), ConditionalField(ShortField('HardTimeout', None), lambda pkt: pkt.Type == 11), ConditionalField(LongField('NumberOfPacketsTransferred', None), lambda pkt: pkt.Type == 11), ConditionalField(LongField('NumberOfOctetsTransferred', None), lambda pkt: pkt.Type == 11), # Port Status Notification message body ConditionalField(ByteField('PortStatusNotificationReason', None), lambda pkt: pkt.Type == 12), ConditionalField(XByteField('PortStatusNotificationPad', None), lambda pkt: pkt.Type == 12), ConditionalField( _PacketField('PortStatusNotification<PortDescriptors>', None, PortDescriptorField_v1_3, 39), lambda pkt: pkt.Type == 12), # Packet Output message body ConditionalField(IntField('PacketOutputPacketBufferID', None), lambda pkt: pkt.Type == 13), ConditionalField(IntField('PacketOutputIngress<PortNumber>', None), lambda pkt: pkt.Type == 13), ConditionalField(ShortField('LengthOfActionDescriptors', None), lambda pkt: pkt.Type == 13), ConditionalField(XByteField('PacketOutputPad', None), lambda pkt: pkt.Type == 13), ConditionalField( _PacketField('PacketOutput<ActionDescriptors>', None, ActionDescriptorField_v1_3, 5), lambda pkt: pkt.Type == 13), # Flow Modification message body ConditionalField(LongField('FlowModificationCookie', None), lambda pkt: pkt.Type == 14), ConditionalField(XLongField('FlowModificationCookieMask', None), lambda pkt: pkt.Type == 14), ConditionalField(ByteField('FlowModificationTableID', None), lambda pkt: pkt.Type == 14), ConditionalField(ByteField('FlowModificationCommand', None), lambda pkt: pkt.Type == 14), ConditionalField(ShortField('FlowModificationIdleTimeout', None), lambda pkt: pkt.Type == 14), ConditionalField(ShortField('FlowModificationHardTimeout', None), lambda pkt: pkt.Type == 14), ConditionalField(ShortField('FlowModificationPriority', None), lambda pkt: pkt.Type == 14), ConditionalField(IntField('FlowModificationPacketBufferID', None), lambda pkt: pkt.Type == 14), ConditionalField(IntField('FlowModificationOutputPort', None), lambda pkt: pkt.Type == 14), ConditionalField(IntField('FlowModificationOutputGroup', None), lambda pkt: pkt.Type == 14), ConditionalField(XShortField('FlowModificationFlags', None), lambda pkt: pkt.Type == 14), ConditionalField(XByteField('FlowModificationPad', None), lambda pkt: pkt.Type == 14), # Group Modification message body ConditionalField(ShortField('GroupModificationCommand', None), lambda pkt: pkt.Type == 15), ConditionalField(ByteField('GroupModificationType', None), lambda pkt: pkt.Type == 15), ConditionalField(ByteField('GroupModificationPad', None), lambda pkt: pkt.Type == 15), ConditionalField(IntField('GroupModificationGroupID', None), lambda pkt: pkt.Type == 15), ConditionalField( _PacketField('GroupModificationBucket', None, OpenFlowBucket_v1_3, 18), lambda pkt: pkt.Type == 15), # Port Modification message body ConditionalField(ShortField('PortModification<PortNumber>', None), lambda pkt: pkt.Type == 16), ConditionalField(XByteField('PortModificationPad', None), lambda pkt: pkt.Type == 16), ConditionalField(MACField('PortModificationEthernetAddress', None), lambda pkt: pkt.Type == 16), ConditionalField(XByteField('PortModificationPad2', None), lambda pkt: pkt.Type == 16), ConditionalField(XIntField('<PortConfigurationFlags>', None), lambda pkt: pkt.Type == 16), ConditionalField(XIntField('<PortConfigurationFlags>Mask', None), lambda pkt: pkt.Type == 16), ConditionalField(XIntField('<PortConfigurationFlags>Advertise', None), lambda pkt: pkt.Type == 16), ConditionalField(XByteField('PortModificationPad3', None), lambda pkt: pkt.Type == 16), # Table Modification message body ConditionalField(ByteField('TableModificationTableID', None), lambda pkt: pkt.Type == 17), ConditionalField(XByteField('TableModificationPad', None), lambda pkt: pkt.Type == 17), ConditionalField(XIntField('TableModificationConfiguration', None), lambda pkt: pkt.Type == 17), # Multipart Request / Multipart Reply message body ConditionalField(ShortField('MultipartType', None), lambda pkt: pkt.Type in [18, 19]), ConditionalField(XShortField('MultipartFlags', None), lambda pkt: pkt.Type in [18, 19]), ConditionalField(XByteField('MultipartPad', None), lambda pkt: pkt.Type in [18, 19]), ConditionalField(ByteField('MultipartBody', None), lambda pkt: pkt.Type in [18, 19]), # Barrier Reply message body ConditionalField(IntField('BarrierReplyID', None), lambda pkt: pkt.Type == 21), # Queue Get Config Request / Queue Get Config Reply message body ConditionalField(IntField('QueueGetConfigRequestPort', None), lambda pkt: pkt.Type in [22, 23]), ConditionalField(ByteField('QueueGetConfigRequestPad', None), lambda pkt: pkt.Type in [22, 23]), ConditionalField( _PacketField('OpenFlowPacketQueue', None, OpenFlowPacketQueue_v1_3, 16), lambda pkt: pkt.Type == 23), # Role Request / Role Reply message body ConditionalField(IntField('RoleRequestRole', None), lambda pkt: pkt.Type in [24, 25]), ConditionalField(ByteField('RoleRequestPad', None), lambda pkt: pkt.Type in [24, 25]), ConditionalField(LongField('RoleRequestGenerationID', None), lambda pkt: pkt.Type in [24, 25]), # Get Async Reply / Set Async messages body ConditionalField(XIntField('GetAsyncReplyPacketInMask', None), lambda pkt: pkt.Type in [27, 28]), ConditionalField(XIntField('GetAsyncReplyPortStatusMask', None), lambda pkt: pkt.Type in [27, 28]), ConditionalField(XIntField('GetAsyncReplyFlowRemovedMask', None), lambda pkt: pkt.Type in [27, 28]), # Meter Modification message body ConditionalField(ShortField('MeterModificationCommand', None), lambda pkt: pkt.Type == 29), ConditionalField(XShortField('MeterModificationFlags', None), lambda pkt: pkt.Type == 29), ConditionalField(IntField('MeterModificationMeterID', None), lambda pkt: pkt.Type == 29), ConditionalField( _PacketField('MeterModificationMeterBand', None, OpenFlowMeterBand_v1_3, 12), lambda pkt: pkt.Type == 29), StrField('Payload', None), ]
class OpenFlowBody_v1_0(Packet): """ OpenFlow Packet v1.0 """ name = 'OpenFlowBody_v1_0' fields_desc = [ # Header ByteEnumField('Type', None, ofp_v1_0_message_type), ShortField('Length', None), IntField('ID', None), # Error message body ConditionalField(ShortField('ErrorType', None), lambda pkt: pkt.Type == 1), ConditionalField(ShortField('ErrorCode', None), lambda pkt: pkt.Type == 1), # Echo Request / Echo Reply message body ConditionalField(StrField('Data', None), lambda pkt: pkt.Type in [2, 3]), # Vendor message body ConditionalField(IntField('VendorID', None), lambda pkt: pkt.Type == 4), # Features Reply message body ConditionalField(XLongField('DatapathID', None), lambda pkt: pkt.Type == 6), ConditionalField(IntField('AvailableNumberOfPacketsCanBeHeld', None), lambda pkt: pkt.Type == 6), ConditionalField(ByteField('NumberOfFlowTabs', None), lambda pkt: pkt.Type == 6), ConditionalField(X3BytesField('FeaturesReplyReserved', None), lambda pkt: pkt.Type == 6), ConditionalField(XIntField('<SwitchCapabilityFlags>', None), lambda pkt: pkt.Type == 6), ConditionalField(XIntField('ActionCapabilityFlags', None), lambda pkt: pkt.Type == 6), ConditionalField( _PacketField('FeaturesReply<PortDescriptors>', None, PortDescriptorField_v1_0, 48), lambda pkt: pkt.Type == 6), # Get Config Reply / Set Config message body ConditionalField(XShortField('SwitchConfigurationFlags', None), lambda pkt: pkt.Type in [8, 9]), ConditionalField(ShortField('MissSendLength', None), lambda pkt: pkt.Type in [8, 9]), # Packet Input Notification message body ConditionalField( IntField('PacketInputNotificationPacketBufferID', None), lambda pkt: pkt.Type == 10), ConditionalField(ShortField('EthernetFrameLength', None), lambda pkt: pkt.Type == 10), ConditionalField( ShortField('PacketInputNotificationIngresss<PortNumber>', None), lambda pkt: pkt.Type == 10), ConditionalField(ByteField('PacketInputNotificationReason', None), lambda pkt: pkt.Type == 10), ConditionalField(XByteField('PacketInputNotificationReserved', None), lambda pkt: pkt.Type == 10), ConditionalField( StrLenField('EthenretFrame', None, length_from=lambda pkt: pkt.EthernetFrameLength), lambda pkt: pkt.Type == 10), # Flow Removed Notification message body ConditionalField( _PacketField('FlowRemovedNotification<FlowMatchDescriptor>', None, FlowMatchDescriptorField_v1_0, 40), lambda pkt: pkt.Type == 11), ConditionalField(ShortField('FlowRemovedNotificationPriority', None), lambda pkt: pkt.Type == 11), ConditionalField(ByteField('FlowRemovedNotificationReason', None), lambda pkt: pkt.Type == 11), ConditionalField(XByteField('FlowRemovedNotificationReserved', None), lambda pkt: pkt.Type == 11), ConditionalField(IntField('LifetimeDuration', None), lambda pkt: pkt.Type == 11), ConditionalField( ShortField('FlowRemovedNotificationSoftLifetime', None), lambda pkt: pkt.Type == 11), ConditionalField( StrFixedLenField('FlowRemovedNotification_Reserved', None, 48), lambda pkt: pkt.Type == 11), ConditionalField(LongField('NumberOfPacketsTransferred', None), lambda pkt: pkt.Type == 11), ConditionalField(LongField('NumberOfOctetsTransferred', None), lambda pkt: pkt.Type == 11), # Port Status Notification message body ConditionalField(ByteField('PortStatusNotificationReason', None), lambda pkt: pkt.Type == 12), ConditionalField( StrFixedLenField('PortStatusNotificationReserved', None, 64), lambda pkt: pkt.Type == 12), ConditionalField( _PacketField('PortStatusNotification<PortDescriptors>', None, PortDescriptorField_v1_0, 48), lambda pkt: pkt.Type == 12), # Packet Output message body ConditionalField(IntField('PacketOutputPacketBufferID', None), lambda pkt: pkt.Type == 13), ConditionalField(ShortField('PacketOutputIngress<PortNumber>', None), lambda pkt: pkt.Type == 13), ConditionalField(ShortField('LengthOfActionDescriptors', None), lambda pkt: pkt.Type == 13), ConditionalField( _PacketField('PacketOutput<ActionDescriptors>', None, ActionDescriptorField_v1_0), ## ???? bytes ## lambda pkt: pkt.Type == 13), ConditionalField(StrField('<PacketData>', None), lambda pkt: pkt.Type == 13), # Flow Modification message body ConditionalField( _PacketField('FlowModification<FlowMatchDescriptor>', None, FlowMatchDescriptorField_v1_0, 40), lambda pkt: pkt.Type == 14), ConditionalField(ShortField('Command', None), lambda pkt: pkt.Type == 14), ConditionalField(ShortField('FlowModificationSoftLifetime', None), lambda pkt: pkt.Type == 14), ConditionalField(ShortField('HardLifetime', None), lambda pkt: pkt.Type == 14), ConditionalField(ShortField('FlowModificationPriority', None), lambda pkt: pkt.Type == 14), ConditionalField(IntField('FlowModificationPacketBufferID', None), lambda pkt: pkt.Type == 14), ConditionalField( ShortField('FlowModificationEgress<PortNumber>', None), lambda pkt: pkt.Type == 14), ConditionalField(XShortField('FlowModificationCU', None), lambda pkt: pkt.Type == 14), ConditionalField(XIntField('FlowModificationReserved', None), lambda pkt: pkt.Type == 14), ConditionalField( _PacketField('FlowModification<ActionDescriptors>', None, ActionDescriptorField_v1_0), ## ???? bytes lambda pkt: pkt.Type == 14), # Port Modification message body ConditionalField(ShortField('PortModification<PortNumber>', None), lambda pkt: pkt.Type == 15), ConditionalField(MACField('Ethernet Address', None), lambda pkt: pkt.Type == 15), ConditionalField(XIntField('<PortConfigurationFlags>', None), lambda pkt: pkt.Type == 15), ConditionalField(XIntField('<PortConfigurationFlags>Mask', None), lambda pkt: pkt.Type == 15), ConditionalField(XIntField('<PortFeatureFlags>', None), lambda pkt: pkt.Type == 15), # Stats Request message body ConditionalField( _PacketField('StatsRequest', None, StatsRequestBody_v1_0, 48), lambda pkt: pkt.Type == 16), # Stats Reply message body ConditionalField( _PacketField('StatsReply', None, StatsReplyBody_v1_0), ## ???? bytes lambda pkt: pkt.Type == 17), StrField('Payload', None), ]
class ActionDescriptorField_v1_0(Packet): """ OpenFlow Action Descriptor Field """ name = 'ActionDescriptorField_v1_0' fields_desc = [ ByteEnumField('Type', None, ofp_v1_0_action_descriptor_type), ShortField('Length', None), # Output Action Descriptor ConditionalField(ShortField('Egress<PortNumber>', None), lambda pkt: pkt.Type == 0), ConditionalField(ShortField('MaxLength', None), lambda pkt: pkt.Type == 0), # VLAN VID Action Descriptor ConditionalField(XShortField('CU+802.1QVID', None), lambda pkt: pkt.Type == 1), ConditionalField(XShortField('VLANVIDReserved', None), lambda pkt: pkt.Type == 1), # VLAN PCP Action Descriptor ConditionalField(XByteField('CU+PCP', None), lambda pkt: pkt.Type == 2), ConditionalField(X3BytesField('VLANPCPReserved', None), lambda pkt: pkt.Type == 2), # Strip VLAN tag Action Descriptor ConditionalField(XIntField('StripVLANTagReserved', None), lambda pkt: pkt.Type == 3), # Ethernet Address Action Descriptor (Ethernet source address) / # Ethernet Address Action Descriptor (Ethernet destination address) ConditionalField( SourceMACField(MACField('EthernetSourceAddress', None)), lambda pkt: pkt.Type == 4), ConditionalField( DestMACField(MACField('EthernetDestinationAddress', None)), lambda pkt: pkt.Type == 5), ConditionalField(StrFixedLenField('EthernetAddressReserved', None, 48), lambda pkt: pkt.Type in [4, 5]), # IPv4 Address Action Descriptor (IPv4 source address) / # IPv4 Address Action Descriptor (IPv4 destination address) ConditionalField(SourceIPField('IPv4SourceAddress', None), lambda pkt: pkt.Type == 6), ConditionalField(IPField('IPv4DestinationAddress', None), lambda pkt: pkt.Type == 7), # IPv4 DSCP Action Descriptor ConditionalField(ByteField('IPv4DSCP+CU', None), lambda pkt: pkt.Type == 8), ConditionalField(X3BytesField('IPv4DSCPReserved', None), lambda pkt: pkt.Type == 8), # TCP/UDP Port Action Descriptor (TCP/UDP source port) / # TCP/UDP Port Action Descriptor (TCP/UDP destination port) ConditionalField(ShortField('SourcePort', None), lambda pkt: pkt.Type == 9), ConditionalField(ShortField('DestinationPort', None), lambda pkt: pkt.Type == 10), ConditionalField(ShortField('TCP/UDPReserved', None), lambda pkt: pkt.Type in [9, 10]), # Vendor Action Descriptor ConditionalField(IntField('VendorID', None), lambda pkt: pkt.Type == 65535), ]
class FitnessPayload(OptionalExtended): fields_desc = ([ByteField('data_page_number', None)] + [ ConditionalField(f, lambda p: p.data_page_number == 16) for f in [ ByteEnumField('equip_type', 0, {}), ByteField('elapsed_time', 0), ByteField('distance_traveled', 0), LEShortField('speed', 0), ByteField('heart_rate', 0), BitField('capabilities', 0, 4), BitField('fe_status', 0, 4), ] ] + [ ConditionalField(f, lambda p: p.data_page_number == 17) for f in [ ByteField('reserved_1', 0), ByteField('reserved_2', 0), ByteField('cycle_length', 0), LEShortField('incline', 0), ByteField('resistance_level', 0), BitField('capabilities', 0, 4), BitField('fe_status', 0, 4), ] ] + [ ConditionalField(f, lambda p: p.data_page_number == 25) for f in [ ByteField('update_event_count', 0), ByteField('instant_cadence', 0), LEShortField('accum_power', 0), InstantPowerField('instant_power', 0), TSBField('trainer_status', 0), BitEnumField( 'target_power', 0, 2, { 0x0: 'at_target_power', 0x1: 'speed_too_low', 0x2: 'speed_too_high', 0x3: 'undetermined', }, ), BitField('reserved', 0, 2), BitEnumField( 'hr_data_source', 0, 2, { 0x0: 'invalid', 0x1: 'ANT+', 0x2: 'HRM', 0x3: 'Contact Sensor' }, ), BitEnumField('distance_traveled_enabled', 0, 1, { 0x0: 'no', 0x1: 'yes' }), BitEnumField('speed_flag', 0, 1, { 0x0: 'real_speed', 0x1: 'virtual_speed' }), ] ] + [ ConditionalField(f, lambda p: p.data_page_number == 26) for f in [ ByteField('update_event_count', 0), ByteField('wheel_ticks', 0), LEShortField('wheel_period', 0), LEShortField('accum_torque', 0), BitField('capabilities', 0, 4), BitField('fe_status', 0, 4), ] ] + [ ConditionalField(f, lambda p: p.data_page_number == 80) for f in [ ByteField('reserved1', 0xFF), ByteField('reserved2', 0xFF), ByteField('hw_revision', 0), LEShortField('manufacturer_id', 0), LEShortField('model_number', 0), ] ] + [ ConditionalField(f, lambda p: p.data_page_number == 81) for f in [ ByteField('reserved', 0xFF), ByteField('sw_revision_supplemental', 0), ByteField('sw_revision', 0), LEIntField('serial_number', 0), ] ]) def post_dissection(self, pkt): if self.data_page_number not in [16, 17, 25, 26, 80, 81]: msg = f'Unknown fitness data page {self.data_page_number}' log.error(msg)