mirror of https://github.com/secdev/scapy.git
Implementation of GMLAN Protocol for Scapy
This commit is contained in:
parent
0968c4aa25
commit
515e0e8165
|
@ -0,0 +1,9 @@
|
|||
# This file is part of Scapy
|
||||
# See http://www.secdev.org/projects/scapy for more informations
|
||||
# Copyright (C) Nils Weiss <nils@we155.de>
|
||||
# This program is published under a GPLv2 license
|
||||
|
||||
"""
|
||||
Package of contrib automotive gm specific modules
|
||||
that have to be loaded explicitly.
|
||||
"""
|
|
@ -0,0 +1,627 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
# This file is part of Scapy
|
||||
# See http://www.secdev.org/projects/scapy for more informations
|
||||
# Copyright (C) Nils Weiss <nils@we155.de>
|
||||
# Copyright (C) Enrico Pozzobon <enrico.pozzobon@gmail.com>
|
||||
# This program is published under a GPLv2 license
|
||||
|
||||
|
||||
import struct
|
||||
from scapy.fields import ObservableDict, XByteEnumField, ByteEnumField, \
|
||||
ConditionalField, XByteField, StrField, XShortEnumField, XShortField, \
|
||||
X3BytesField, XIntField, ShortField, PacketField, PacketListField, \
|
||||
FieldListField
|
||||
from scapy.packet import Packet, bind_layers
|
||||
from scapy.config import conf
|
||||
from scapy.error import warning
|
||||
|
||||
|
||||
"""
|
||||
GMLAN
|
||||
"""
|
||||
|
||||
conf.contribs['GMLAN'] = {'GMLAN_ECU_AddressingScheme': None}
|
||||
|
||||
|
||||
class GMLAN(Packet):
|
||||
@staticmethod
|
||||
def determine_len(x):
|
||||
if conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] is None:
|
||||
warning("Define conf.GMLAN_ECU_AddressingScheme! "
|
||||
"Assign either 2,3 or 4")
|
||||
if conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] \
|
||||
not in [2, 3, 4]:
|
||||
warning("Define conf.GMLAN_ECU_AddressingScheme! "
|
||||
"Assign either 2,3 or 4")
|
||||
return conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] == x
|
||||
|
||||
services = ObservableDict(
|
||||
{0x04: 'ClearDiagnosticInformation',
|
||||
0x10: 'InitiateDiagnosticOperation',
|
||||
0x12: 'ReadFailureRecordData',
|
||||
0x1a: 'ReadDataByIdentifier',
|
||||
0x20: 'ReturnToNormalOperation',
|
||||
0x22: 'ReadDataByParameterIdentifier',
|
||||
0x23: 'ReadMemoryByAddress',
|
||||
0x27: 'SecurityAccess',
|
||||
0x28: 'DisableNormalCommunication',
|
||||
0x2c: 'DynamicallyDefineMessage',
|
||||
0x2d: 'DefinePIDByAddress',
|
||||
0x34: 'RequestDownload',
|
||||
0x36: 'TransferData',
|
||||
0x3b: 'WriteDataByIdentifier',
|
||||
0x3e: 'TesterPresent',
|
||||
0x44: 'ClearDiagnosticInformationPositiveResponse',
|
||||
0x50: 'InitiateDiagnosticOperationPositiveResponse',
|
||||
0x52: 'ReadFailureRecordDataPositiveResponse',
|
||||
0x5a: 'ReadDataByIdentifierPositiveResponse',
|
||||
0x60: 'ReturnToNormalOperationPositiveResponse',
|
||||
0x62: 'ReadDataByParameterIdentifierPositiveResponse',
|
||||
0x63: 'ReadMemoryByAddressPositiveResponse',
|
||||
0x67: 'SecurityAccessPositiveResponse',
|
||||
0x68: 'DisableNormalCommunicationPositiveResponse',
|
||||
0x6c: 'DynamicallyDefineMessagePositiveResponse',
|
||||
0x6d: 'DefinePIDByAddressPositiveResponse',
|
||||
0x74: 'RequestDownloadPositiveResponse',
|
||||
0x76: 'TransferDataPositiveResponse',
|
||||
0x7b: 'WriteDataByIdentifierPositiveResponse',
|
||||
0x7e: 'TesterPresentPositiveResponse',
|
||||
0x7f: 'NegativeResponse',
|
||||
0xa2: 'ReportProgrammingState',
|
||||
0xa5: 'ProgrammingMode',
|
||||
0xa9: 'ReadDiagnosticInformation',
|
||||
0xaa: 'ReadDataByPacketIdentifier',
|
||||
0xae: 'DeviceControl',
|
||||
0xe2: 'ReportProgrammingStatePositiveResponse',
|
||||
0xe5: 'ProgrammingModePositiveResponse',
|
||||
0xe9: 'ReadDiagnosticInformationPositiveResponse',
|
||||
0xea: 'ReadDataByPacketIdentifierPositiveResponse',
|
||||
0xee: 'DeviceControlPositiveResponse'})
|
||||
name = 'General Motors Local Area Network'
|
||||
fields_desc = [
|
||||
XByteEnumField('service', 0, services)
|
||||
]
|
||||
|
||||
def answers(self, other):
|
||||
"""DEV: true if self is an answer from other"""
|
||||
if other.__class__ == self.__class__:
|
||||
return (other.service + 0x40) == self.service or \
|
||||
(self.service == 0x7f and
|
||||
(self.requestServiceId == other.service))
|
||||
return 0
|
||||
|
||||
def hashret(self):
|
||||
if self.service == 0x7f:
|
||||
return struct.pack('B', self.requestServiceId)
|
||||
return struct.pack('B', self.service & ~0x40)
|
||||
|
||||
|
||||
# ########################IDO###################################
|
||||
class GMLAN_IDO(Packet):
|
||||
subfunctions = {
|
||||
0x02: 'disableAllDTCs',
|
||||
0x03: 'enableDTCsDuringDevCntrl',
|
||||
0x04: 'wakeUpLinks'}
|
||||
name = 'InitiateDiagnosticOperation'
|
||||
fields_desc = [
|
||||
ByteEnumField('subfunction', 0, subfunctions)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_IDO, service=0x10)
|
||||
|
||||
|
||||
# ########################RFRD###################################
|
||||
class GMLAN_DTC(Packet):
|
||||
name = 'GMLAN DTC information'
|
||||
fields_desc = [
|
||||
XByteField('failureRecordNumber', 0),
|
||||
XByteField('DTCHighByte', 0),
|
||||
XByteField('DTCLowByte', 0),
|
||||
XByteField('DTCFailureType', 0)
|
||||
]
|
||||
|
||||
def extract_padding(self, p):
|
||||
return "", p
|
||||
|
||||
|
||||
class GMLAN_RFRD(Packet):
|
||||
subfunctions = {
|
||||
0x01: 'readFailureRecordIdentifiers',
|
||||
0x02: 'readFailureRecordParameters'}
|
||||
name = 'ReadFailureRecordData'
|
||||
fields_desc = [
|
||||
ByteEnumField('subfunction', 0, subfunctions),
|
||||
ConditionalField(PacketField("dtc", b'', GMLAN_DTC),
|
||||
lambda pkt: pkt.subfunction == 0x02)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RFRD, service=0x12)
|
||||
|
||||
|
||||
class GMLAN_RFRDPR(Packet):
|
||||
name = 'ReadFailureRecordDataPositiveResponse'
|
||||
fields_desc = [
|
||||
ByteEnumField('subfunction', 0, GMLAN_RFRD.subfunctions)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RFRDPR, service=0x52)
|
||||
|
||||
|
||||
class GMLAN_RFRDPR_RFRI(Packet):
|
||||
failureRecordDataStructureIdentifiers = {
|
||||
0x00: "PID",
|
||||
0x01: "DPID"
|
||||
}
|
||||
name = 'ReadFailureRecordDataPositiveResponse_readFailureRecordIdentifiers'
|
||||
fields_desc = [
|
||||
ByteEnumField('failureRecordDataStructureIdentifier', 0,
|
||||
failureRecordDataStructureIdentifiers),
|
||||
PacketListField("dtcs", [], GMLAN_DTC)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN_RFRDPR, GMLAN_RFRDPR_RFRI, subfunction=0x01)
|
||||
|
||||
|
||||
class GMLAN_RFRDPR_RFRP(Packet):
|
||||
name = 'ReadFailureRecordDataPositiveResponse_readFailureRecordParameters'
|
||||
fields_desc = [
|
||||
PacketField("dtc", b'', GMLAN_DTC)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN_RFRDPR, GMLAN_RFRDPR_RFRP, subfunction=0x02)
|
||||
|
||||
|
||||
# ########################RDBI###################################
|
||||
class GMLAN_RDBI(Packet):
|
||||
dataIdentifiers = ObservableDict({
|
||||
0x90: "$90: VehicleIdentificationNumber (VIN)",
|
||||
0x92: "$92: SystemSupplierId (SYSSUPPID)",
|
||||
0x97: "$97: SystemNameOrEngineType (SNOET)",
|
||||
0x98: "$98: RepairShopCodeOrTesterSerialNumber (RSCOTSN)",
|
||||
0x99: "$99: ProgrammingDate (PD)",
|
||||
0x9a: "$9a: DiagnosticDataIdentifier (DDI)",
|
||||
0x9b: "$9b: XmlConfigurationCompatibilityIdentifier (XMLCCID)",
|
||||
0x9C: "$9C: XmlDataFilePartNumber (XMLDFPN)",
|
||||
0x9D: "$9D: XmlDataFileAlphaCode (XMLDFAC)",
|
||||
0x9F: "$9F: PreviousStoredRepairShopCodeOrTesterSerialNumbers "
|
||||
"(PSRSCOTSN)",
|
||||
0xA0: "$A0: manufacturers_enable_counter (MEC)",
|
||||
0xA1: "$A1: ECUConfigurationOrCustomizationData (ECUCOCGD) 1",
|
||||
0xA2: "$A2: ECUConfigurationOrCustomizationData (ECUCOCGD) 2",
|
||||
0xA3: "$A3: ECUConfigurationOrCustomizationData (ECUCOCGD) 3",
|
||||
0xA4: "$A4: ECUConfigurationOrCustomizationData (ECUCOCGD) 4",
|
||||
0xA5: "$A5: ECUConfigurationOrCustomizationData (ECUCOCGD) 5",
|
||||
0xA6: "$A6: ECUConfigurationOrCustomizationData (ECUCOCGD) 6",
|
||||
0xA7: "$A7: ECUConfigurationOrCustomizationData (ECUCOCGD) 7",
|
||||
0xA8: "$A8: ECUConfigurationOrCustomizationData (ECUCOCGD) 8",
|
||||
0xB0: "$B0: ECUDiagnosticAddress (ECUADDR)",
|
||||
0xB1: "$B1: ECUFunctionalSystemsAndVirtualDevices (ECUFSAVD)",
|
||||
0xB2: "$B2: GM ManufacturingData (GMMD)",
|
||||
0xB3: "$B3: Data Universal Numbering System Identification (DUNS)",
|
||||
0xB4: "$B4: Manufacturing Traceability Characters (MTC)",
|
||||
0xB5: "$B5: GM BroadcastCode (GMBC)",
|
||||
0xB6: "$B6: GM Target Vehicle (GMTV)",
|
||||
0xB7: "$B7: GM Software Usage Description (GMSUD)",
|
||||
0xB8: "$B8: GM Bench Verification Information (GMBVI)",
|
||||
0xB9: "$B9: Subnet_Config_List_HighSpeed (SCLHS)",
|
||||
0xBA: "$BA: Subnet_Config_List_LowSpeed (SCLLS)",
|
||||
0xBB: "$BB: Subnet_Config_List_MidSpeed (SCLMS)",
|
||||
0xBC: "$BC: Subnet_Config_List_NonCan 1 (SCLNC 1)",
|
||||
0xBD: "$BD: Subnet_Config_List_NonCan 2 (SCLNC 2)",
|
||||
0xBE: "$BE: Subnet_Config_List_LIN (SCLLIN)",
|
||||
0xBF: "$BF: Subnet_Config_List_GMLANChassisExpansionBus (SCLGCEB)",
|
||||
0xC0: "$C0: BootSoftwarePartNumber (BSPN)",
|
||||
0xC1: "$C1: SoftwareModuleIdentifier (SWMI) 01",
|
||||
0xC2: "$C2: SoftwareModuleIdentifier (SWMI) 02",
|
||||
0xC3: "$C3: SoftwareModuleIdentifier (SWMI) 03",
|
||||
0xC4: "$C4: SoftwareModuleIdentifier (SWMI) 04",
|
||||
0xC5: "$C5: SoftwareModuleIdentifier (SWMI) 05",
|
||||
0xC6: "$C6: SoftwareModuleIdentifier (SWMI) 06",
|
||||
0xC7: "$C7: SoftwareModuleIdentifier (SWMI) 07",
|
||||
0xC8: "$C8: SoftwareModuleIdentifier (SWMI) 08",
|
||||
0xC9: "$C9: SoftwareModuleIdentifier (SWMI) 09",
|
||||
0xCA: "$CA: SoftwareModuleIdentifier (SWMI) 10",
|
||||
0xCB: "$CB: EndModelPartNumber",
|
||||
0xCC: "$CC: BaseModelPartNumber (BMPN)",
|
||||
0xD0: "$D0: BootSoftwarePartNumberAlphaCode",
|
||||
0xD1: "$D1: SoftwareModuleIdentifierAlphaCode (SWMIAC) 01",
|
||||
0xD2: "$D2: SoftwareModuleIdentifierAlphaCode (SWMIAC) 02",
|
||||
0xD3: "$D3: SoftwareModuleIdentifierAlphaCode (SWMIAC) 03",
|
||||
0xD4: "$D4: SoftwareModuleIdentifierAlphaCode (SWMIAC) 04",
|
||||
0xD5: "$D5: SoftwareModuleIdentifierAlphaCode (SWMIAC) 05",
|
||||
0xD6: "$D6: SoftwareModuleIdentifierAlphaCode (SWMIAC) 06",
|
||||
0xD7: "$D7: SoftwareModuleIdentifierAlphaCode (SWMIAC) 07",
|
||||
0xD8: "$D8: SoftwareModuleIdentifierAlphaCode (SWMIAC) 08",
|
||||
0xD9: "$D9: SoftwareModuleIdentifierAlphaCode (SWMIAC) 09",
|
||||
0xDA: "$DA: SoftwareModuleIdentifierAlphaCode (SWMIAC) 10",
|
||||
0xDB: "$DB: EndModelPartNumberAlphaCode",
|
||||
0xDC: "$DC: BaseModelPartNumberAlphaCode",
|
||||
0xDD: "$DD: SoftwareModuleIdentifierDataIdentifiers (SWMIDID)",
|
||||
0xDE: "$DE: GMLANIdentificationData (GMLANID)",
|
||||
0xDF: "$DF: ECUOdometerValue (ECUODO)",
|
||||
0xE0: "$E0: VehicleLevelDataRecord (VLDR) 0",
|
||||
0xE1: "$E1: VehicleLevelDataRecord (VLDR) 1",
|
||||
0xE2: "$E2: VehicleLevelDataRecord (VLDR) 2",
|
||||
0xE3: "$E3: VehicleLevelDataRecord (VLDR) 3",
|
||||
0xE4: "$E4: VehicleLevelDataRecord (VLDR) 4",
|
||||
0xE5: "$E5: VehicleLevelDataRecord (VLDR) 5",
|
||||
0xE6: "$E6: VehicleLevelDataRecord (VLDR) 6",
|
||||
0xE7: "$E7: VehicleLevelDataRecord (VLDR) 7",
|
||||
0xE8: "$E8: Subnet_Config_List_GMLANPowertrainExpansionBus (SCLGPEB)",
|
||||
0xE9: "$E9: Subnet_Config_List_GMLANFrontObjectExpansionBus "
|
||||
"(SCLGFOEB)",
|
||||
0xEA: "$EA: Subnet_Config_List_GMLANRearObjectExpansionBus (SCLGROEB)",
|
||||
0xEB: "$EB: Subnet_Config_List_GMLANExpansionBus1 (SCLGEB1)",
|
||||
0xEC: "$EC: Subnet_Config_List_GMLANExpansionBus2 (SCLGEB2)",
|
||||
0xED: "$ED: Subnet_Config_List_GMLANExpansionBus3 (SCLGEB3)",
|
||||
0xEE: "$EE: Subnet_Config_List_GMLANExpansionBus4 (SCLGEB4)",
|
||||
0xEF: "$EF: Subnet_Config_List_GMLANExpansionBus5 (SCLGEB5)",
|
||||
})
|
||||
|
||||
name = 'ReadDataByIdentifier'
|
||||
fields_desc = [
|
||||
XByteEnumField('dataIdentifier', 0, dataIdentifiers)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RDBI, service=0x1A)
|
||||
|
||||
|
||||
class GMLAN_RDBIPR(Packet):
|
||||
name = 'ReadDataByIdentifierPositiveResponse'
|
||||
fields_desc = [
|
||||
XByteEnumField('dataIdentifier', 0, GMLAN_RDBI.dataIdentifiers),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RDBIPR, service=0x5A)
|
||||
|
||||
|
||||
# ########################RDBI###################################
|
||||
class GMLAN_RDBPI(Packet):
|
||||
dataIdentifiers = ObservableDict({
|
||||
0x0005: "OBD_EngineCoolantTemperature",
|
||||
0x000C: "OBD_EngineRPM",
|
||||
0x001f: "OBD_TimeSinceEngineStart"
|
||||
})
|
||||
name = 'ReadDataByParameterIdentifier'
|
||||
fields_desc = [
|
||||
FieldListField("identifiers", [],
|
||||
XShortEnumField('parameterIdentifier', 0,
|
||||
dataIdentifiers))
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RDBPI, service=0x22)
|
||||
|
||||
|
||||
class GMLAN_RDBPIPR(Packet):
|
||||
name = 'ReadDataByParameterIdentifierPositiveResponse'
|
||||
fields_desc = [
|
||||
XShortEnumField('parameterIdentifier', 0, GMLAN_RDBPI.dataIdentifiers),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RDBPIPR, service=0x62)
|
||||
|
||||
|
||||
# ########################RDBPKTI###################################
|
||||
class GMLAN_RDBPKTI(Packet):
|
||||
name = 'ReadDataByPacketIdentifier'
|
||||
subfunctions = {
|
||||
0x00: "stopSending",
|
||||
0x01: "sendOneResponse",
|
||||
0x02: "scheduleAtSlowRate",
|
||||
0x03: "scheduleAtMediumRate",
|
||||
0x04: "scheduleAtFastRate"
|
||||
}
|
||||
|
||||
fields_desc = [
|
||||
XByteEnumField('subfunction', 0, subfunctions),
|
||||
ConditionalField(StrField('request_DPIDs', b''),
|
||||
lambda pkt: pkt.subfunction > 0x0)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RDBPKTI, service=0xAA)
|
||||
|
||||
|
||||
# ########################RMBA###################################
|
||||
class GMLAN_RMBA(Packet):
|
||||
name = 'ReadMemoryByAddress'
|
||||
fields_desc = [
|
||||
ConditionalField(XShortField('memoryAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(2)),
|
||||
ConditionalField(X3BytesField('memoryAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(3)),
|
||||
ConditionalField(XIntField('memoryAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(4)),
|
||||
XShortField('memorySize', 0),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RMBA, service=0x23)
|
||||
|
||||
|
||||
class GMLAN_RMBAPR(Packet):
|
||||
name = 'ReadMemoryByAddressPositiveResponse'
|
||||
fields_desc = [
|
||||
StrField('dataRecord', None, fmt="B")
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RMBAPR, service=0x63)
|
||||
|
||||
|
||||
# ########################SA###################################
|
||||
class GMLAN_SA(Packet):
|
||||
subfunctions = {
|
||||
0: 'ReservedByDocument',
|
||||
1: 'SPSrequestSeed',
|
||||
2: 'SPSsendKey',
|
||||
3: 'DevCtrlrequestSeed',
|
||||
4: 'DevCtrlsendKey',
|
||||
255: 'ReservedByDocument'}
|
||||
for i in range(0x05, 0x0a + 1):
|
||||
subfunctions[i] = 'ReservedByDocument'
|
||||
for i in range(0x0b, 0xfa + 1):
|
||||
subfunctions[i] = 'Reserved for vehicle manufacturer specific needs'
|
||||
for i in range(0xfb, 0xfe + 1):
|
||||
subfunctions[i] = 'Reserved for ECU or ' \
|
||||
'system supplier manufacturing needs'
|
||||
|
||||
name = 'SecurityAccess'
|
||||
fields_desc = [
|
||||
ByteEnumField('subfunction', 0, subfunctions),
|
||||
ConditionalField(XShortField('securityKey', B""),
|
||||
lambda pkt: pkt.subfunction % 2 == 0)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_SA, service=0x27)
|
||||
|
||||
|
||||
class GMLAN_SAPR(Packet):
|
||||
name = 'SecurityAccessPositiveResponse'
|
||||
fields_desc = [
|
||||
ByteEnumField('subfunction', 0, GMLAN_SA.subfunctions),
|
||||
ConditionalField(XShortField('securitySeed', B""),
|
||||
lambda pkt: pkt.subfunction % 2 == 1),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_SAPR, service=0x67)
|
||||
|
||||
|
||||
# ########################DDM###################################
|
||||
class GMLAN_DDM(Packet):
|
||||
name = 'DynamicallyDefineMessage'
|
||||
fields_desc = [
|
||||
XByteField('DPIDIdentifier', 0),
|
||||
StrField('PIDData', b'\x00\x00')
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_DDM, service=0x2C)
|
||||
|
||||
|
||||
class GMLAN_DDMPR(Packet):
|
||||
name = 'DynamicallyDefineMessagePositiveResponse'
|
||||
fields_desc = [
|
||||
XByteField('DPIDIdentifier', 0)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_DDMPR, service=0x6C)
|
||||
|
||||
|
||||
# ########################DPBA###################################
|
||||
class GMLAN_DPBA(Packet):
|
||||
name = 'DefinePIDByAddress'
|
||||
fields_desc = [
|
||||
XShortField('parameterIdentifier', 0),
|
||||
ConditionalField(XShortField('memoryAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(2)),
|
||||
ConditionalField(X3BytesField('memoryAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(3)),
|
||||
ConditionalField(XIntField('memoryAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(4)),
|
||||
XByteField('memorySize', 0),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_DPBA, service=0x2D)
|
||||
|
||||
|
||||
class GMLAN_DPBAPR(Packet):
|
||||
name = 'DefinePIDByAddressPositiveResponse'
|
||||
fields_desc = [
|
||||
XShortField('parameterIdentifier', 0),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_DPBA, service=0x6D)
|
||||
|
||||
|
||||
# ########################RD###################################
|
||||
class GMLAN_RD(Packet):
|
||||
name = 'RequestDownload'
|
||||
fields_desc = [
|
||||
XByteField('dataFormatIdentifier', 0),
|
||||
ConditionalField(XShortField('memorySize', 0),
|
||||
lambda pkt: GMLAN.determine_len(2)),
|
||||
ConditionalField(X3BytesField('memorySize', 0),
|
||||
lambda pkt: GMLAN.determine_len(3)),
|
||||
ConditionalField(XIntField('memorySize', 0),
|
||||
lambda pkt: GMLAN.determine_len(4)),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RD, service=0x34)
|
||||
|
||||
|
||||
# ########################TD###################################
|
||||
class GMLAN_TD(Packet):
|
||||
subfunctions = {
|
||||
0x00: "download",
|
||||
0x80: "downloadAndExecuteOrExecute"
|
||||
}
|
||||
name = 'TransferData'
|
||||
fields_desc = [
|
||||
ByteEnumField('subfunction', 0, subfunctions),
|
||||
ConditionalField(XShortField('startingAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(2)),
|
||||
ConditionalField(X3BytesField('startingAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(3)),
|
||||
ConditionalField(XIntField('startingAddress', 0),
|
||||
lambda pkt: GMLAN.determine_len(4)),
|
||||
StrField("dataRecord", None)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_TD, service=0x36)
|
||||
|
||||
|
||||
# ########################WDBI###################################
|
||||
class GMLAN_WDBI(Packet):
|
||||
name = 'WriteDataByIdentifier'
|
||||
fields_desc = [
|
||||
XByteEnumField('dataIdentifier', 0, GMLAN_RDBI.dataIdentifiers),
|
||||
StrField("dataRecord", b'\x00')
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_WDBI, service=0x3B)
|
||||
|
||||
|
||||
class GMLAN_WDBIPR(Packet):
|
||||
name = 'WriteDataByIdentifierPositiveResponse'
|
||||
fields_desc = [
|
||||
XByteEnumField('dataIdentifier', 0, GMLAN_RDBI.dataIdentifiers)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_WDBIPR, service=0x7B)
|
||||
|
||||
|
||||
# ########################RPSPR###################################
|
||||
class GMLAN_RPSPR(Packet):
|
||||
programmedStates = {
|
||||
0x00: "fully programmed",
|
||||
0x01: "no op s/w or cal data",
|
||||
0x02: "op s/w present, cal data missing",
|
||||
0x03: "s/w present, default or no start cal present",
|
||||
0x50: "General Memory Fault",
|
||||
0x51: "RAM Memory Fault",
|
||||
0x52: "NVRAM Memory Fault",
|
||||
0x53: "Boot Memory Failure",
|
||||
0x54: "Flash Memory Failure",
|
||||
0x55: "EEPROM Memory Failure",
|
||||
}
|
||||
name = 'ReportProgrammedStatePositiveResponse'
|
||||
fields_desc = [
|
||||
ByteEnumField('programmedState', 0, programmedStates),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RPSPR, service=0xE2)
|
||||
|
||||
|
||||
# ########################PM###################################
|
||||
class GMLAN_PM(Packet):
|
||||
subfunctions = {
|
||||
0x01: "requestProgrammingMode",
|
||||
0x02: "requestProgrammingMode_HighSpeed",
|
||||
0x03: "enableProgrammingMode"
|
||||
}
|
||||
name = 'ProgrammingMode'
|
||||
fields_desc = [
|
||||
ByteEnumField('subfunction', 0, subfunctions),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_PM, service=0xA5)
|
||||
|
||||
|
||||
# ########################RDI###################################
|
||||
class GMLAN_RDI(Packet):
|
||||
subfunctions = {
|
||||
0x80: 'readStatusOfDTCByDTCNumber',
|
||||
0x81: 'readStatusOfDTCByStatusMask',
|
||||
0x82: 'sendOnChangeDTCCount'
|
||||
}
|
||||
name = 'ReadDiagnosticInformation'
|
||||
fields_desc = [
|
||||
ByteEnumField('subfunction', 0, subfunctions)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_RDI, service=0xA9)
|
||||
|
||||
|
||||
class GMLAN_RDI_BN(Packet):
|
||||
name = 'ReadStatusOfDTCByDTCNumber'
|
||||
fields_desc = [
|
||||
XByteField('DTCHighByte', 0),
|
||||
XByteField('DTCLowByte', 0),
|
||||
XByteField('DTCFailureType', 0),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN_RDI, GMLAN_RDI_BN, subfunction=0x80)
|
||||
|
||||
|
||||
class GMLAN_RDI_BM(Packet):
|
||||
name = 'ReadStatusOfDTCByStatusMask'
|
||||
fields_desc = [
|
||||
XByteField('DTCStatusMask', 0),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN_RDI, GMLAN_RDI_BM, subfunction=0x81)
|
||||
|
||||
|
||||
class GMLAN_RDI_BC(Packet):
|
||||
name = 'SendOnChangeDTCCount'
|
||||
fields_desc = [
|
||||
XByteField('DTCStatusMask', 0),
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN_RDI, GMLAN_RDI_BC, subfunction=0x82)
|
||||
# TODO:This function receive single frame responses... (Implement GMLAN Socket)
|
||||
|
||||
|
||||
# ########################NRC###################################
|
||||
class GMLAN_NR(Packet):
|
||||
negativeResponseCodes = {
|
||||
0x11: 'ServiceNotSupported',
|
||||
0x12: 'SubFunctionNotSupported',
|
||||
0x22: 'ConditionsNotCorrectOrRequestSequenceError',
|
||||
0x31: 'RequestOutOfRange',
|
||||
0x35: 'InvalidKey',
|
||||
0x36: 'ExceedNumberOfAttempts',
|
||||
0x37: 'RequiredTimeDelayNotExpired',
|
||||
0x78: 'RequestCorrectlyReceived-ResponsePending',
|
||||
0x81: 'SchedulerFull',
|
||||
0x83: 'VoltageOutOfRange',
|
||||
0x85: 'GeneralProgrammingFailure',
|
||||
0x89: 'DeviceTypeError',
|
||||
0x99: 'ReadyForDownload-DTCStored',
|
||||
0xe3: 'DeviceControlLimitsExceeded',
|
||||
}
|
||||
name = 'NegativeResponse'
|
||||
fields_desc = [
|
||||
XByteEnumField('requestServiceId', 0, GMLAN.services),
|
||||
ByteEnumField('returnCode', 0, negativeResponseCodes),
|
||||
ShortField('deviceControlLimitExceeded', 0)
|
||||
]
|
||||
|
||||
|
||||
bind_layers(GMLAN, GMLAN_NR, service=0x7f)
|
|
@ -0,0 +1,367 @@
|
|||
# gmlan unit tests
|
||||
#
|
||||
# Type the following command to launch start the tests:
|
||||
# $ sudo bash test/run_tests -t test/gmlan.uts -F
|
||||
|
||||
% gmlan unit tests
|
||||
|
||||
+ Configuration of scapy
|
||||
= Load gmlan layer
|
||||
~ conf command
|
||||
|
||||
load_contrib('automotive.gm.gmlan')
|
||||
|
||||
+ Basic Packet Tests()
|
||||
= Set GMLAN ECU AddressingScheme
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 2
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] == 2
|
||||
|
||||
= Craft Packet
|
||||
x = GMLAN(b'\x52\x02\x01\x16\x71\x00\x00\x0c\xaa\xbb')
|
||||
x.load == b'\x00\x0c\xaa\xbb'
|
||||
x.service == 0x52
|
||||
|
||||
= Craft VIN Packet
|
||||
x = GMLAN(b'\x5a\x90'+ raw("WOOOJBF35W1042000"))
|
||||
x.load == b'WOOOJBF35W1042000'
|
||||
x.dataIdentifier == 0x90
|
||||
|
||||
= Test Packet with ECU AddressingScheme2
|
||||
x = GMLAN()/GMLAN_RMBA(b'\x11\x22\x44\x22')
|
||||
x.memoryAddress == 0x1122
|
||||
x.memorySize == 0x4422
|
||||
|
||||
= Craft Packet with ECU AddressingScheme2
|
||||
y = GMLAN()/GMLAN_RMBA(memoryAddress=0x1122, memorySize=0x4422)
|
||||
bytes(x) == bytes(y)
|
||||
|
||||
= Test Packet with ECU AddressingScheme3
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 3
|
||||
x = GMLAN()/GMLAN_RMBA(b'\x11\x22\x44\x22\x11')
|
||||
x.memoryAddress == 0x112244
|
||||
x.memorySize == 0x2211
|
||||
|
||||
= Craft Packet with ECU AddressingScheme3
|
||||
y = GMLAN()/GMLAN_RMBA(memoryAddress=0x112244, memorySize=0x2211)
|
||||
bytes(x) == bytes(y)
|
||||
|
||||
= Test Packet with ECU AddressingScheme4
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 4
|
||||
x = GMLAN()/GMLAN_RMBA(b'\x11\x22\x44\x22\x11\x00')
|
||||
x.memoryAddress == 0x11224422
|
||||
x.memorySize == 0x1100
|
||||
|
||||
= Craft Packet with ECU AddressingScheme4
|
||||
y = GMLAN()/GMLAN_RMBA(memoryAddress=0x11224422, memorySize=0x1100)
|
||||
bytes(x) == bytes(y)
|
||||
|
||||
= Craft Packet for RequestDownload2
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 2
|
||||
x = GMLAN(b'\x34\x12\x08\x15')
|
||||
x.service == 0x34
|
||||
x.dataFormatIdentifier == 0x12
|
||||
x.memorySize == 0x815
|
||||
|
||||
y = GMLAN()/GMLAN_RD(dataFormatIdentifier=0x12, memorySize=0x815)
|
||||
bytes(y) == bytes(x)
|
||||
|
||||
= Craft Packet for RequestDownload3
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 3
|
||||
x = GMLAN(b'\x34\x12\x08\x15\x00')
|
||||
x.service == 0x34
|
||||
x.dataFormatIdentifier == 0x12
|
||||
x.memorySize == 0x81500
|
||||
|
||||
y = GMLAN()/GMLAN_RD(dataFormatIdentifier=0x12, memorySize=0x81500)
|
||||
bytes(y) == bytes(x)
|
||||
|
||||
= Craft Packet for RequestDownload4
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 4
|
||||
x = GMLAN(b'\x34\x12\x08\x15\x00\x11')
|
||||
x.service == 0x34
|
||||
x.dataFormatIdentifier == 0x12
|
||||
x.memorySize == 0x8150011
|
||||
|
||||
= Craft Packet for RFRD1
|
||||
x = GMLAN(b'\x12\x01')
|
||||
x.service == 0x12
|
||||
x.subfunction == 1
|
||||
|
||||
= Craft Packet for RFRD2
|
||||
x = GMLAN(b'\x12\x02\x01\x02\x03\x04')
|
||||
x.service == 0x12
|
||||
x.subfunction == 2
|
||||
x.dtc.failureRecordNumber == 1
|
||||
x.dtc.DTCHighByte == 2
|
||||
x.dtc.DTCLowByte == 3
|
||||
x.dtc.DTCFailureType == 4
|
||||
|
||||
= Craft Packet for RFRDPR_RFRI
|
||||
x = GMLAN(b'\x52\x01\x00\x01\x02\x03\x04')
|
||||
x.service == 0x52
|
||||
x.subfunction == 1
|
||||
x.failureRecordDataStructureIdentifier == 0
|
||||
x.dtcs[0].failureRecordNumber == 1
|
||||
x.dtcs[0].DTCHighByte == 2
|
||||
x.dtcs[0].DTCLowByte == 3
|
||||
x.dtcs[0].DTCFailureType == 4
|
||||
|
||||
= Craft Packet for RFRDPR_RFRI
|
||||
x = GMLAN(b'\x52\x01\x00\x01\x02\x03\x04\x01\x02\x03\x04\x01\x02\x03\x04\x01\x02\x03\x04')
|
||||
x.service == 0x52
|
||||
x.subfunction == 1
|
||||
x.failureRecordDataStructureIdentifier == 0
|
||||
x.dtcs[0].failureRecordNumber == 1
|
||||
x.dtcs[0].DTCHighByte == 2
|
||||
x.dtcs[0].DTCLowByte == 3
|
||||
x.dtcs[0].DTCFailureType == 4
|
||||
x.dtcs[1].failureRecordNumber == 1
|
||||
x.dtcs[1].DTCHighByte == 2
|
||||
x.dtcs[1].DTCLowByte == 3
|
||||
x.dtcs[1].DTCFailureType == 4
|
||||
x.dtcs[2].failureRecordNumber == 1
|
||||
x.dtcs[2].DTCHighByte == 2
|
||||
x.dtcs[2].DTCLowByte == 3
|
||||
x.dtcs[2].DTCFailureType == 4
|
||||
x.dtcs[3].failureRecordNumber == 1
|
||||
x.dtcs[3].DTCHighByte == 2
|
||||
x.dtcs[3].DTCLowByte == 3
|
||||
x.dtcs[3].DTCFailureType == 4
|
||||
|
||||
= Craft Packet for RFRDPR_RFRP
|
||||
x = GMLAN(b'\x52\x02\x01\x02\x03\x04deadbeef')
|
||||
x.service == 0x52
|
||||
x.subfunction == 2
|
||||
x.dtc.failureRecordNumber == 1
|
||||
x.dtc.DTCHighByte == 2
|
||||
x.dtc.DTCLowByte == 3
|
||||
x.dtc.DTCFailureType == 4
|
||||
x.show()
|
||||
x.load == b'deadbeef'
|
||||
|
||||
|
||||
= Craft Packet for RDBI
|
||||
x = GMLAN(b'\x1A\x11')
|
||||
x.service == 0x1A
|
||||
x.dataIdentifier == 0x11
|
||||
|
||||
= Craft Packet for RDBIPR
|
||||
x = GMLAN(b'\x5A\x11deadbeef')
|
||||
x.service == 0x5A
|
||||
x.dataIdentifier == 0x11
|
||||
x.load == b'deadbeef'
|
||||
|
||||
= Craft Packet for RDBPI
|
||||
x = GMLAN(b'\x22\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88\x99\x99')
|
||||
x.service == 0x22
|
||||
x.identifiers[0] == 0x1111
|
||||
x.identifiers[1] == 0x2222
|
||||
x.identifiers[2] == 0x3333
|
||||
x.identifiers[3] == 0x4444
|
||||
x.identifiers[4] == 0x5555
|
||||
x.identifiers[5] == 0x6666
|
||||
x.identifiers[6] == 0x7777
|
||||
x.identifiers[7] == 0x8888
|
||||
x.identifiers[8] == 0x9999
|
||||
|
||||
= Craft Packet for RDBPIPR
|
||||
x = GMLAN(b'\x62\x00\x11deadbeef')
|
||||
x.service == 0x62
|
||||
x.parameterIdentifier == 0x11
|
||||
x.load == b'deadbeef'
|
||||
|
||||
= Craft Packet for GMLAN_RDBPKTI1
|
||||
x = GMLAN(b'\xAA\x01deadbeef')
|
||||
x.service == 0xAA
|
||||
x.subfunction == 0x01
|
||||
x.request_DPIDs == b'deadbeef'
|
||||
|
||||
= Craft Packet for GMLAN_RDBPKTI2
|
||||
x = GMLAN(b'\xAA\x00')
|
||||
x.service == 0xAA
|
||||
x.subfunction == 0
|
||||
|
||||
= Craft Packet for GMLAN_SA1
|
||||
x = GMLAN(b'\x27\x01')
|
||||
x.service == 0x27
|
||||
x.subfunction == 1
|
||||
|
||||
= Craft Packet for GMLAN_SA2
|
||||
x = GMLAN(b'\x27\x02\xde\xad')
|
||||
x.service == 0x27
|
||||
x.subfunction == 2
|
||||
x.securityKey == 0xdead
|
||||
|
||||
= Craft Packet for GMLAN_SAPR1
|
||||
x = GMLAN(b'\x67\x02')
|
||||
x.service == 0x67
|
||||
x.subfunction == 2
|
||||
|
||||
= Craft Packet for GMLAN_SAPR2
|
||||
x = GMLAN(b'\x67\x01\xde\xad')
|
||||
x.service == 0x67
|
||||
x.subfunction == 1
|
||||
x.securitySeed == 0xdead
|
||||
|
||||
= Craft Packet for GMLAN_DDM
|
||||
x = GMLAN(b'\x2c\x02dead')
|
||||
x.service == 0x2c
|
||||
x.DPIDIdentifier == 2
|
||||
x.PIDData == b'dead'
|
||||
|
||||
= Craft Packet for GMLAN_DDMPR
|
||||
x = GMLAN(b'\x6c\x02dead')
|
||||
x.service == 0x6c
|
||||
x.DPIDIdentifier == 2
|
||||
|
||||
= Craft Packet for GMLAN_DPBA1
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 2
|
||||
x = GMLAN(b'\x2D\x02\x02\x11\x11\x33')
|
||||
x.service == 0x2d
|
||||
x.parameterIdentifier == 0x202
|
||||
x.memoryAddress == 0x1111
|
||||
x.memorySize == 0x33
|
||||
|
||||
= Craft Packet for GMLAN_DPBA2
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 3
|
||||
x = GMLAN(b'\x2D\x02\x02\x11\x11\x11\x33')
|
||||
x.service == 0x2d
|
||||
x.parameterIdentifier == 0x202
|
||||
x.memoryAddress == 0x111111
|
||||
x.memorySize == 0x33
|
||||
|
||||
= Craft Packet for GMLAN_DPBA3
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 4
|
||||
x = GMLAN(b'\x2D\x02\x02\x11\x11\x11\x11\x33')
|
||||
x.service == 0x2d
|
||||
x.parameterIdentifier == 0x202
|
||||
x.memoryAddress == 0x11111111
|
||||
x.memorySize == 0x33
|
||||
|
||||
= Craft Packet for GMLAN_DPBAPR
|
||||
x = GMLAN(b'\x6D\x02\x02')
|
||||
x.service == 0x6d
|
||||
x.parameterIdentifier == 0x202
|
||||
|
||||
= Craft Packet for GMLAN_RD1
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 2
|
||||
x = GMLAN(b'\x34\x02\x11\x11')
|
||||
x.service == 0x34
|
||||
x.dataFormatIdentifier == 0x2
|
||||
x.memorySize == 0x1111
|
||||
|
||||
= Craft Packet for GMLAN_RD2
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 3
|
||||
x = GMLAN(b'\x34\x02\x11\x11\x11')
|
||||
x.service == 0x34
|
||||
x.dataFormatIdentifier == 0x2
|
||||
x.memorySize == 0x111111
|
||||
|
||||
= Craft Packet for GMLAN_RD3
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 4
|
||||
x = GMLAN(b'\x34\x02\x11\x11\x11\x11')
|
||||
x.service == 0x34
|
||||
x.dataFormatIdentifier == 0x2
|
||||
x.memorySize == 0x11111111
|
||||
|
||||
= Craft Packet for GMLAN_TD1
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 2
|
||||
x = GMLAN(b'\x36\x02\x11\x11dead')
|
||||
x.service == 0x36
|
||||
x.subfunction == 0x2
|
||||
x.startingAddress == 0x1111
|
||||
x.dataRecord == b'dead'
|
||||
|
||||
= Craft Packet for GMLAN_TD2
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 3
|
||||
x = GMLAN(b'\x36\x02\x11\x11\x11dead')
|
||||
x.service == 0x36
|
||||
x.subfunction == 0x2
|
||||
x.startingAddress == 0x111111
|
||||
x.dataRecord == b'dead'
|
||||
|
||||
= Craft Packet for GMLAN_TD3
|
||||
conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme'] = 4
|
||||
x = GMLAN(b'\x36\x02\x11\x11\x11\x11dead')
|
||||
x.service == 0x36
|
||||
x.subfunction == 0x2
|
||||
x.startingAddress == 0x11111111
|
||||
x.dataRecord == b'dead'
|
||||
|
||||
= Craft Packet for WDBI
|
||||
x = GMLAN(b'\x3b\x11deadbeef')
|
||||
x.service == 0x3b
|
||||
x.dataIdentifier == 0x11
|
||||
x.dataRecord == b'deadbeef'
|
||||
|
||||
= Craft Packet for WDBIPR
|
||||
x = GMLAN(b'\x7b\x11')
|
||||
x.service == 0x7b
|
||||
x.dataIdentifier == 0x11
|
||||
|
||||
= Craft Packet for RPSPR
|
||||
x = GMLAN(b'\xe2\x11')
|
||||
x.service == 0xe2
|
||||
x.programmedState == 0x11
|
||||
|
||||
= Craft Packet for PM
|
||||
x = GMLAN(b'\xA5\x11')
|
||||
x.service == 0xA5
|
||||
x.subfunction == 0x11
|
||||
|
||||
= Craft Packet for RDI
|
||||
x = GMLAN(b'\xA9\x11')
|
||||
x.service == 0xA9
|
||||
x.subfunction == 0x11
|
||||
|
||||
= Craft Packet for RDI_BN
|
||||
x = GMLAN(b'\xA9\x80\x11\x22\x33')
|
||||
x.service == 0xA9
|
||||
x.subfunction == 0x80
|
||||
x.DTCHighByte == 0x11
|
||||
x.DTCLowByte == 0x22
|
||||
x.DTCFailureType == 0x33
|
||||
|
||||
= Craft Packet for RDI_BM1
|
||||
x = GMLAN(b'\xA9\x81\x11')
|
||||
x.service == 0xA9
|
||||
x.subfunction == 0x81
|
||||
x.DTCStatusMask == 0x11
|
||||
|
||||
= Craft Packet for RDI_BM2
|
||||
x = GMLAN(b'\xA9\x82\x11')
|
||||
x.service == 0xA9
|
||||
x.subfunction == 0x82
|
||||
x.DTCStatusMask == 0x11
|
||||
|
||||
= Craft Packet for NR
|
||||
x = GMLAN(b'\x7f\x11\x00\x11\x22')
|
||||
x.service == 0x7f
|
||||
x.requestServiceId == 0x11
|
||||
x.returnCode == 0
|
||||
x.deviceControlLimitExceeded == 0x1122
|
||||
|
||||
= Check not answers
|
||||
y = GMLAN(b'\x11deadbeef')
|
||||
x = GMLAN(b'\x7f\x10\x00\x11\x22')
|
||||
assert not x.answers(y)
|
||||
|
||||
= Check answers 1
|
||||
y = GMLAN(b'\x10deadbeef')
|
||||
x = GMLAN(b'\x7f\x10\x00\x11\x22')
|
||||
assert x.answers(y)
|
||||
|
||||
= Check hashret 1
|
||||
print(y.hashret())
|
||||
print(x.hashret())
|
||||
|
||||
y.hashret() == x.hashret()
|
||||
|
||||
= Check answers 2
|
||||
y = GMLAN()/GMLAN_SA(subfunction=1)
|
||||
x = GMLAN()/GMLAN_SAPR()
|
||||
assert x.answers(y)
|
||||
|
||||
= Check hashret 2
|
||||
y.hashret() == x.hashret()
|
||||
|
Loading…
Reference in New Issue