Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

All "Supported Cars" need to move to fingerprinting 2.0 #1238

Closed
4 tasks
geohot opened this issue Mar 13, 2020 · 13 comments
Closed
4 tasks

All "Supported Cars" need to move to fingerprinting 2.0 #1238

geohot opened this issue Mar 13, 2020 · 13 comments
Milestone

Comments

@geohot
Copy link
Contributor

geohot commented Mar 13, 2020

Move fingerprinting 1.0, and subsequently white/grey panda, to "Community Maintained." Honda and Toyota are already good.

  • Chrysler/Jeep
  • Hyundai/Kia
  • Subaru
  • Volkswagen

After these 4 are migrated, we can move all of fingerprinting 1.0 to community maintained.

@geohot geohot added this to the 0.8 milestone Mar 13, 2020
@pd0wm
Copy link
Contributor

pd0wm commented Mar 14, 2020

Do you want to try spending some time on fingerprinting 2.0 through a giraffe? Then we can remove the code completely.

@arne182
Copy link
Contributor

arne182 commented Mar 14, 2020

To maintain this. Which I don't mind doing I would like to have access our at least get the sentry unrecognised car errors. The partial can messages that are captured give a good enough indication of the car type and possible missing signals

@jyoung8607
Copy link
Collaborator

jyoung8607 commented Mar 15, 2020

Move fingerprinting 1.0, and subsequently white/grey panda, to "Community Maintained." Honda and Toyota are already good.

  • Volkswagen

I'm actively looking at this, because fingerprinting 1.0 doesn't really work for VW anyway. The current OP and Panda example UDS query code tries to work, and it elicits partial responses from a few addresses, but it doesn't fully succeed on anything at this time.

This week I'll be snooping diagnostic comms from VCDS to see what the difference is. I have a hypothesis that some things are fine with UDS over ISO-TP but some things may need UDS over VW/Bosch CAN TP 1.6 or 2.0, because German Engineering™. To be verified.

Once we get comms working to the steering rack, I'm confident we can use it for high quality fingerprinting. The racks are widely shared between vehicles, but can be queried for a four-digit number that identifies what assist characteristic map it was loaded with, which lets us discriminate between harder cases like the 16,384 VW Golf variants, etc.

@martinl
Copy link
Contributor

martinl commented Mar 15, 2020

I have done some testing with FW fingerprinting on Subaru Crosstrek 2018

I used discovered ECU addresses from fw_versions.py scan and ran some ISO-TP queries using panda

  • All discovered ECU-s respond to following Subaru OBD Mode 22 queries
SSMID (22 F1 00) - 3 byte ECU identifier
ROMID (22 F1 82) - 4-8 byte ECU ROM identifier
System String (22 F1 97) - ECU description string (eg Power Steering System)
  • Only engine and transmission ECU-s respond to OBD calibration ID (09 04) query
  • 5 non-essential (A/C, Keyless Entry, ..) ECU-s respond to vendor-specific Version String (22 F1 89) query

ROM ID seems promising enough for testing FW fingerprinting, so I set up subaru-fw-fingerprinting branch and added experimental Subaru FW query and Impreza FW fingerprint for getting some feedback from other Subaru users

@pd0wm
Copy link
Contributor

pd0wm commented Mar 16, 2020

Nice work! Looking forward to the PRs to add this :)

Once we have the query shipped for a brand I can help going through all the logs on our side and fill the database with all the versions we got back.

@jyoung8607
Copy link
Collaborator

After a weekend of tinkering and traffic monitoring, with some ugly local hacks, I have fw_versions.py talking to 17 of the 29 control modules in my 2018 Golf R / VW MQB. I can get to more of them if I need to, but I've already got the most important ones. There are three obstacles to deal with before I can upstream a solution:

  1. UDS/OBD_VERSION_REQUEST are basically useless for us, so we'll need another query type in fw_versions.py much like Subaru above. Best bet for VW will be 0xF187 VEHICLE_MANUFACTURER_SPARE_PART_NUMBER or similar.

  2. The ISO-TP RX addr is normally TX addr + 0x8, and that holds true for the ECU which sits at the standard 0x7e0, but everything else uses TX addr + 0x6A. I gather the offsets used are not standard and there's a decent variety among manufacturers. Shotgunning every offset and messaging style combination at every address will take too long. It might make sense to expand the vehicle FW_VERSIONS ( Ecu, TX addr, subaddr ) tuples to include an (optional?) RX address.

  3. The ESC module, which would be be really nice to fingerprint, consistently sends a "please wait" negative response (0x78 "requestCorrectlyReceived-ResponsePending") before responding. The Panda UDS client library knows how to deal with that, but isotp_parallel_query doesn't, at least not without adding yet another duplicate query variant that would have to be tried on everything.

Example session with ABS/ESC that embodies all three issues above:

TX 0x713,0x0210035555555555,8 Hey ABS/ESC module, can we talk?
RX 0x77d,0x065003003201f4aa,8 Sure, what's up?
TX 0x713,0x0322f18755555555,8 Can you tell me your part number?
RX 0x77d,0x037f2278aaaaaaaa,8 No. Well, maybe later.
RX 0x77d,0x100e62f187355130,8 Okay fine, here it is ... are you getting it?
TX 0x713,0x3000015555555555,8 Sure, keep going.
RX 0x77d,0x2136313435313743,8 ...
RX 0x77d,0x2252aaaaaaaaaaaa,8 ... it's "5Q0614517CR".

Partial examples for 0xF187 VEHICLE_MANUFACTURER_SPARE_PART_NUMBER:

(Ecu.eps, 0x712, None): [b'3Q0909144L '] (EPS)
(Ecu.gateway, 0x710, None): [b'3Q0907530L '] (CAN gateway)
(Ecu.unknown, 0x70a, None): [b'5QA919294B '] (Park distance control)
(Ecu.unknown, 0x70e, None): [b'5Q0937085BN'] (BCM)
(Ecu.unknown, 0x715, None): [b'5Q0959655J '] (Airbags)
(Ecu.unknown, 0x71c, None): [b'5G0907159D '] (Fake engine noise maker)
(Ecu.unknown, 0x731, None): [b'5Q0905861A '] (Steering column lock)
(Ecu.unknown, 0x732, None): [b'5Q0959435C '] (Keyless entry / security)
(Ecu.unknown, 0x746, None): [b'5G0907044CF'] (Auto HVAC)
(Ecu.unknown, 0x74a, None): [b'5Q0959593E '] (Driver's side door)
(Ecu.unknown, 0x74b, None): [b'5Q0959592E '] (Passenger's side doors)
(Ecu.unknown, 0x74f, None): [b'3Q0980654H '] (LKAS camera)
(Ecu.unknown, 0x757, None): [b'5Q0907572J '] (Forward radar)
(Ecu.unknown, 0x76f, None): [b'5Q0035456A '] (Sound system amplifier)
(Ecu.unknown, 0x772, None): [b'5Q0907376B '] (Dynamic suspension controls)

VW are ridiculously good at parts-bin sharing on this platform, so a lot of the stuff won't identify in a way that helps you tell VW MQB vehicles apart. To make a very long story short, we want to ask the airbag module at 0x715 for data ID 0xF187.

  • It's not optional, it's always there
  • The part number it identifies with is extremely specific to the model/chassis
  • Per-model variants are limited, and updates / replacements / supersessions are quite rare
  • I can actually pre-populate the per-model PN lists right out of the VW global parts catalog
  • I don't have to solve problem 3 yet

From that we'll know enough about the car to assign a good-enough model name, wheelbase, mass, and PIF tune. Later on, if we really need to distinguish between Golf/Golf GTI/Golf R, or Audi A3/S3/RS3, we can mix in the ABS/ESC controller and probably get what we need.

Last thought...

Can I just skip all this and use the VIN? Seriously. I know you had some sort of problem with Honda/Toyota, but if the VIN starts with a Volkswagen factory WMI, I know for a fact that looking at the 7th and 8th digits gets me what I need, going back at least 25 years. It's about the same info I'd get from identifying the airbag module. We get the VIN for free on BP/C2, and I can even get it from a broadcast message on White/Grey Panda (community only, sure). I'll have to use VIN on the upcoming PQ35/PQ46/NMS port, because that stuff is too old to speak UDS.

If you're amenable to "Fingerprinting 2.0" using VIN as an optional part of the mix, I'd much rather go that way for VW, and I'm willing to put in the work.

@gregjhogan
Copy link
Member

What does the manufacturer (ODIS?) diagnostic software for VW use to check if a firmware update available applies to the connected vehicle? Part of the goal is to ensure the driving interface is correct (if there are differences the firmware is different/updated).

@jyoung8607
Copy link
Collaborator

jyoung8607 commented Mar 22, 2020

ODIS will check the combination of the software/spare part number and the software version number. See page 7 here: https://static.nhtsa.gov/odi/tsbs/2018/MC-10149864-9999.pdf

I don't have ODIS handy, but Ross-Tech VCDS will get identical data. Example:

Address 15: Airbags (J234)       Labels:| 5Q0-959-655.clb
Part No SW: 5Q0 959 655 J    HW: 5Q0 959 655 J
Component: AirbagVW20    010 0830  
Serial number: 003GCR09SK3W
Coding: 8CCCFC00000000005000001AC24800000065
Shop #: WSC 01357 011 00200
ASAM Dataset: EV_AirbaVW20SMEVW37X 002144

In this case, either 0xF187 or 0xF188 returns "5Q0959655J" for the SW part number, and 0xF189 returns "0830" for the SW version. For this particular module, the reported 0xF188 SW and 0xF191 HW part numbers are the same, but that's definitely not always the case.

Here's the same ECU list as my earlier comment, but queried with 0xF189 instead of 0xF187:

(Ecu.eps, 0x712, None): [b'5081'] (EPS)
(Ecu.gateway, 0x710, None): [b'4326'] (CAN gateway)
(Ecu.unknown, 0x70a, None): [b'0044'] (Park distance control)
(Ecu.unknown, 0x70c, None): [b'0140'] (Steering wheel controls)
(Ecu.unknown, 0x70e, None): [b'0253'] (BCM)
(Ecu.unknown, 0x70f, None): [b'7084'] (Haldex AWD controller)
(Ecu.unknown, 0x713, None): [b'0523'] (ABS brakes)
(Ecu.unknown, 0x715, None): [b'0830'] (Airbags)
(Ecu.unknown, 0x71c, None): [b'0001'] (Fake engine noise maker)
(Ecu.unknown, 0x731, None): [b'0120'] (Steering column lock)
(Ecu.unknown, 0x732, None): [b'0803'] (Keyless entry / security)
(Ecu.unknown, 0x746, None): [b'1801'] (Auto HVAC)
(Ecu.unknown, 0x74a, None): [b'0041'] (Driver's side doors)
(Ecu.unknown, 0x74b, None): [b'0041'] (Passenger's side doors)
(Ecu.unknown, 0x74e, None): [b'0080'] (Lane Change Assist / RCTA)
(Ecu.unknown, 0x74f, None): [b'0272'] (LKAS camera)
(Ecu.unknown, 0x757, None): [b'0654'] (Forward radar)
(Ecu.unknown, 0x76f, None): [b'0200'] (Sound system amplifier)
(Ecu.unknown, 0x772, None): [b'0121'] (Dynamic suspension controls)

The only module that responded to UDS/OBD_VERSION_REQUEST was the engine ECU, everything else I needed these different queries for.

If there's ever a functional change, something that would change the APIs or behaviors or other software contract matters, something that would make it suitable or unsuitable as a replacement part in a given car, the software part number will change. If it's a bugfix only, it's true that sometimes only the software version will change.

I get what you're saying about verifying firmware versions for safety purposes, but we have to identify the car too, and I'm not convinced the SW version numbers alone will work for us. We could potentially collect both. Or, and this would probably be easier, I'd be very amenable to looking at both the VIN and UDS SW version numbers together.

@pd0wm
Copy link
Contributor

pd0wm commented Mar 23, 2020

When I was looking into the WMI for Honda/Toyota it was a complete mess. None of the lists I found online was complete. Each one I found had ones the others didn't and then I saw ones in the incoming data that was in none of the lists. Then there is also Japan, where they don't use VIN but a "frame number" which on Toyota gets returned instead when you query VIN (https://en.wikipedia.org/wiki/Japanese_domestic_market#VIN).

tl;dr. Is there a good source for WMI for VW that also works in Japan? Maybe this list is complete since it's maintained by the Germans?

@jyoung8607
Copy link
Collaborator

jyoung8607 commented Mar 23, 2020

I just pulled up a VIN for a 2014 Golf GTI that was supposedly manufactured for the Japanese market and it looks quite traditional to me: WVWZZZAUZEW24000 (last 4 digits zeroed to not dox the owner). I went to PartsLink24 to check its factory build sheet and it's definitely made for Japan:

PR-8ZK Aerials - Antenna for AM/FM reception, "diversity" (for Japan)
PR-0VR Owner's manuals - Information kit in Japanese
PR-6W4 Front license plate carrier - Front license plate carrier (small, Japan)
PR-ER5 Regional code for radio - Regional code "Japan" for radio
PR-0SL Special labels/plates - Labels in Japanese

The only market I was even a little worried about was China, because my PartsLink24 subscription doesn't work on cars made over there. But since then I've gotten a 2017 Audi A3 from China and although I'd never seen that WMI before, it has a legitimate Audi A3 chassis code (8V) and otherwise looks like a standard VIN: LFV2A28V4H5050000

VW's own ODIS software used on Volkswagen, Audi, SEAT, Škoda, Bentley and Lamborghini, as well as third-party diagnostic software like VCDS, all look at that 7th and 8th digit chassis code to decide what sort of car it is. I can't speak for all cars from all manufacturers, but I've been immersed in the international VW scene for many years before OP came into existence and I'm very confident we can make VINs work for us.

Proposal:

If you're concerned about VINs being variable format, like JDM frame numbers, let's treat them as such. Let each port optionally be able to "claim" a VIN (or pseudo-VIN) with a pure regex instead of worrying about WMIs per se. Here's a regex that would match everybody on the VW community port right now:

^((WVW)|(1V2)|(TMB)|(3VW)|(WAU)|(WVG)|(LFV)).{14}$

Naturally if no port claims the VIN, or a port doesn't have a claim regex, OP would keep doing fingerprinting as it was before, so we don't have to boil the ocean solving VINs for every supported port all at once, or ever.

If a VIN claim regex gets a match, that port's CARs become the only candidates. We could have another optional per-CAR MODEL_VINS regex dict in each port to identify candidate CARs within the port, and then finish up with FW_VERSIONS to verify safe interoperability. Then we're free to run a much smaller set of UDS identification procedures since you don't have to run every possible type of UDS query for every module and every vehicle, just the ones that apply for that port (or sub-selected model(s) from the VIN).

TL;DR: If we do that ^^ stuff, we can make VIN/VW work without breaking anybody else, then you get the benefit of being able to convert other ports when/if/as you wish, and FP 2.0 gets faster.

@jyoung8607
Copy link
Collaborator

jyoung8607 commented Mar 23, 2020

Crappy pseudo-code logic for my proposed approach:

if BP/C2:

    if we got the VIN *and* one or more ports claim the VIN by regex:
        // The new proposed behavior
        // Start off as VW family only, add more down the line when/if/as desired
        candidate list reduced to all CARs in those ports
        if one or more candidate CARs claim the VIN by regex:
            candidate list reduced to those CAR(s)

    else:
        // Fall thru to the exact same behavior FP 2.0 uses today
        // Would exclude VW and its magic query needs and the extra time needed
        candidate list reduced to CARs in ports *without* regex claims at all

    run UDS identification process on candidate list we just generated

    if nothing matches:
       FP 1.0 CAN message constellation ID / community supported???

else:
    FP 1.0 CAN message constellation ID / community supported

Hopefully that make sense. Even if not using it for full model recognition, there's an opportunity to further speed up the UDS query process, which is time sensitive for everyone, by gradually adding at least some VIN recognition to various ports, to focus the set of queries to run.

@gregjhogan
Copy link
Member

Thanks for taking the time to look into this so deeply. It really sounds to me like the combination of the CAN address and software version (0xF189) for VW will work equivalent to Honda and Toyota firmware queries. Our experience has been that different vehicle models/trims with the same hardware have different software versions because the tuning specific to that vehicle is part in the firmware (requiring different software version numbers to properly identify when updates apply). This means that the combination of a set of CAN addrs and version strings does identify vehicles uniquely at the level OP requires. My suggestion is to stick with that unless we can point to situations where that approach is insufficient.

@jyoung8607
Copy link
Collaborator

jyoung8607 commented Apr 27, 2020

I'm attaching a dump of every UDS data value the modules in my car are willing to report from the standardized manufacturer-independent UDS identifier list.

all-type-all-address-query.txt

We got lucky and found the EPS module will report a composite of its per-vehicle parameterization via APPLICATION_DATA_IDENTIFICATION. That has a vehicle type and response curve index embedded in it. This can be used to identify the vehicle with probably good-enough resolution. Here's what it's composed of, drawn from VCDS scan data from several other cars:

steering-map-examples.txt

There are several issues we still need to discuss:

  1. For our purposes, APPLICATION_DATA_IDENTIFICATION is really only useful on the EPS and maybe the airbags. We'd have to make other queries if you want to look at version data from other driving or identification relevant modules, and those are really going to be version checks only. The software versions absolutely do collide between vehicles and are difficult to use for identification. Changing software versions is just not how VW customize modules to vehicles.

As an example, note the 2019 Tiguan and 2019 Golf Alltrack in the attached file share exactly the same HW part num, SW part num, and SW version IDs.

  1. The above solution would accomplish vehicle identification, but not necessarily software version validation. What we're getting isn't the rack software model or version, just the version of the parameterized vehicle-specific data block. So, while it would satisfy the letter requirement of FPv2, it may not satisfy the spirit. It's up to you if that's good enough.

  2. We still need to solve the rx_addr offset issue, but I have a solution I'll propose for that in a separate PR.

  3. We still have very supportables vehicles coming (VW PQ35/PQ46/NMS, if not others) which, depending on age, simply don't speak UDS for diagnostics. This method of fingerprinting simply will not work on those vehicles, without significant effort to support other diagnostic protocols. I can still identify them well-enough by VIN, just like I can identify VW MQB by VIN (although UDS helps to refine).

TL;DR: I still strongly advocate for using the VIN, backed up by UDS validation of versions, as the most correct and future-proof solution. But, I'll file a discussion PR with something that works well-enough to kick the can down the road.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants