Implementation of GMLAN Protocol for Scapy

This commit is contained in:
Nils Weiss 2018-05-07 09:06:33 +02:00
parent 0968c4aa25
commit 515e0e8165
4 changed files with 1004 additions and 0 deletions

View File

@ -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.
"""

View File

@ -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)

View File

@ -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()

View File

@ -64,6 +64,7 @@ setup(
'scapy/contrib',
'scapy/contrib/automotive',
'scapy/contrib/automotive/bmw',
'scapy/contrib/automotive/gm',
'scapy/layers',
'scapy/layers/tls',
'scapy/layers/tls/crypto',