1# SPDX-License-Identifier: GPL-2.0-only 2# This file is part of Scapy 3# See https://scapy.net/ for more information 4# Copyright (C) Andreas Korb <andreas.d.korb@gmail.com> 5# Copyright (C) Nils Weiss <nils@we155.de> 6 7# scapy.contrib.status = skip 8 9from scapy.fields import ByteField, XByteField, BitEnumField, \ 10 PacketListField, XBitField, XByteEnumField, FieldListField, FieldLenField 11from scapy.packet import Packet 12from scapy.contrib.automotive.obd.packet import OBD_Packet 13from scapy.config import conf 14 15 16class OBD_DTC(OBD_Packet): 17 name = "DiagnosticTroubleCode" 18 19 locations = { 20 0b00: 'Powertrain', 21 0b01: 'Chassis', 22 0b10: 'Body', 23 0b11: 'Network', 24 } 25 26 fields_desc = [ 27 BitEnumField('location', 0, 2, locations), 28 XBitField('code1', 0, 2), 29 XBitField('code2', 0, 4), 30 XBitField('code3', 0, 4), 31 XBitField('code4', 0, 4), 32 ] 33 34 35class OBD_NR(Packet): 36 name = "NegativeResponse" 37 38 responses = { 39 0x10: 'generalReject', 40 0x11: 'serviceNotSupported', 41 0x12: 'subFunctionNotSupported-InvalidFormat', 42 0x21: 'busy-RepeatRequest', 43 0x22: 'conditionsNotCorrectOrRequestSequenceError', 44 0x78: 'requestCorrectlyReceived-ResponsePending' 45 } 46 47 fields_desc = [ 48 XByteField('request_service_id', 0), 49 XByteEnumField('response_code', 0, responses) 50 ] 51 52 def answers(self, other): 53 return self.request_service_id == other.service and \ 54 (self.response_code != 0x78 or 55 conf.contribs['OBD']['treat-response-pending-as-answer']) 56 57 58class OBD_S01(Packet): 59 name = "S1_CurrentData" 60 fields_desc = [ 61 FieldListField("pid", [], XByteField('', 0)) 62 ] 63 64 65class OBD_S02_Record(OBD_Packet): 66 fields_desc = [ 67 XByteField('pid', 0), 68 ByteField('frame_no', 0) 69 ] 70 71 72class OBD_S02(Packet): 73 name = "S2_FreezeFrameData" 74 fields_desc = [ 75 PacketListField("requests", [], OBD_S02_Record) 76 ] 77 78 79class OBD_S03(Packet): 80 name = "S3_RequestDTCs" 81 82 83class OBD_S03_PR(Packet): 84 name = "S3_ResponseDTCs" 85 fields_desc = [ 86 FieldLenField('count', None, count_of='dtcs', fmt='B'), 87 PacketListField('dtcs', [], OBD_DTC, count_from=lambda pkt: pkt.count) 88 ] 89 90 def answers(self, other): 91 return isinstance(other, OBD_S03) 92 93 94class OBD_S04(Packet): 95 name = "S4_ClearDTCs" 96 97 98class OBD_S04_PR(Packet): 99 name = "S4_ClearDTCsPositiveResponse" 100 101 def answers(self, other): 102 return isinstance(other, OBD_S04) 103 104 105class OBD_S06(Packet): 106 name = "S6_OnBoardDiagnosticMonitoring" 107 fields_desc = [ 108 FieldListField("mid", [], XByteField('', 0)) 109 ] 110 111 112class OBD_S07(Packet): 113 name = "S7_RequestPendingDTCs" 114 115 116class OBD_S07_PR(Packet): 117 name = "S7_ResponsePendingDTCs" 118 fields_desc = [ 119 FieldLenField('count', None, count_of='dtcs', fmt='B'), 120 PacketListField('dtcs', [], OBD_DTC, count_from=lambda pkt: pkt.count) 121 ] 122 123 def answers(self, other): 124 return isinstance(other, OBD_S07) 125 126 127class OBD_S08(Packet): 128 name = "S8_RequestControlOfSystem" 129 fields_desc = [ 130 FieldListField("tid", [], XByteField('', 0)) 131 ] 132 133 134class OBD_S09(Packet): 135 name = "S9_VehicleInformation" 136 fields_desc = [ 137 FieldListField("iid", [], XByteField('', 0)) 138 ] 139 140 141class OBD_S0A(Packet): 142 name = "S0A_RequestPermanentDTCs" 143 144 145class OBD_S0A_PR(Packet): 146 name = "S0A_ResponsePermanentDTCs" 147 fields_desc = [ 148 FieldLenField('count', None, count_of='dtcs', fmt='B'), 149 PacketListField('dtcs', [], OBD_DTC, count_from=lambda pkt: pkt.count) 150 ] 151 152 def answers(self, other): 153 return isinstance(other, OBD_S0A) 154