DoIP로 요청을 보냈는데 응답이 이렇게 돌아올 때가 있다.
7F xx 22
처음 보면 통신이 불안정해 보인다.
- TCP 연결은 살아 있다
- Routing Activation도 성공했다
- Diagnostic ACK도 보인다
- 그런데 UDS 결과는 실패다
이때 NRC 0x22 Conditions Not Correct를 timeout처럼 보면 오래 헤맨다.
이 응답은 보통 ECU가 요청은 이해했지만 지금 상태에서는 수행할 수 없다고 말하는 쪽에 가깝다.
오늘 메모는 DoIP에서 NRC 0x22가 반복될 때 통신층과 ECU 상태 조건을 어떻게 나눠 봐야 하는지다.
결론부터
0x22는 먼저 아래처럼 보는 편이 빠르다.
DoIP transport 실패
-> TCP 끊김, DoIP NACK, payload length mismatch, 무응답
UDS 조건 미충족
-> 7F xx 22
7F xx 22가 명확히 왔다면
요청은 대체로 ECU 애플리케이션까지 도착한 것이다.
그래서 처음 볼 것은 socket이나 재전송 횟수가 아니라
세션, 보안 레벨, 전원 상태, 이전 작업 상태, 서비스별 precondition이다.
흔한 패턴 1: 세션은 바뀐 줄 알았는데 ECU는 기본 세션이다
가장 흔한 경우는 DiagnosticSessionControl 흐름이 흔들린 상태다.
테스터는 이미 extended session이라고 생각한다.
하지만 ECU는 default session으로 돌아가 있을 수 있다.
Tester:
session = extended 라고 저장
ECU:
session timeout 이후 default로 복귀
이 상태에서 보안 접근, RoutineControl, Download 같은 서비스를 보내면
서비스 자체는 이해하지만 현재 세션 조건이 맞지 않아 0x22가 올 수 있다.
특히 긴 대기 후 첫 요청에서 보이면
Tester Present와 세션 timeout을 같이 봐야 한다.
관련 흐름은 DoIP에서 Session Control 먼저 이해해야 하는 이유와
DoIP에서 Tester Present 왜 계속 보내는 걸까에서 이어진다.
흔한 패턴 2: Security Access가 유지됐다고 가정한다
Security Access는 한 번 성공했다고 영원히 유지되는 상태가 아니다.
아래 이벤트가 끼면 ECU 쪽 보안 문맥이 바뀔 수 있다.
- 세션 변경
- ECU Reset
- TCP 재연결
- 진단 idle timeout
- 다른 테스터의 진입
테스터 내부 변수에는 unlocked=true가 남아 있는데
ECU는 이미 잠긴 상태일 수 있다.
이때 0x33 Security Access Denied가 올 수도 있지만,
서비스 정책에 따라 현재 조건이 맞지 않는다는 의미로 0x22가 먼저 보일 수도 있다.
핵심은 unlock 결과만 로그에 남기지 말고
unlock 이후 어떤 세션과 연결 문맥에서 요청을 보냈는지를 같이 남기는 것이다.
흔한 패턴 3: 전원 모드나 차량 상태 조건을 놓친다
DoIP에서는 TCP가 붙었다고 ECU가 모든 서비스를 받을 준비가 된 것은 아니다.
차량이나 ECU 상태가 서비스 조건에 들어가는 경우가 많다.
예를 들면 이런 식이다.
programming request
-> 특정 전원 모드 필요
routine start
-> 이전 routine 완료 필요
actuator test
-> 안전 조건 만족 필요
그래서 0x22가 오면
패킷 길이보다 먼저 “지금 ECU가 그 기능을 수행할 수 있는 상태인가”를 봐야 한다.
DoIP Entity Status나 Power Mode를 같이 보는 이유도 여기에 있다.
상태 확인 흐름은 DoIP는 붙었는데 진단이 안 된다: Entity Status/Power Mode로 상태부터 확인하기와 잘 맞는다.
흔한 패턴 4: 이전 작업이 아직 끝나지 않았다
긴 RoutineControl이나 Firmware Transfer 흐름에서는
이전 요청의 상태가 다음 요청에 영향을 준다.
예를 들어 이런 순서가 섞이면 헷갈린다.
RoutineControl start
-> Response Pending
-> tester timeout
-> 같은 routine 재요청
-> 7F 31 22
테스터 입장에서는 timeout으로 끝난 요청이다.
하지만 ECU 입장에서는 아직 작업 중일 수 있다.
이때 재시도를 무작정 넣으면 상태가 더 꼬인다.
0x21 Busy Repeat Request, 0x78 Response Pending, 0x22 Conditions Not Correct를 같은 retry 정책으로 묶지 않는 편이 좋다.
각 코드는 비슷하게 “나중에 다시”처럼 보이지만 의미가 다르다.
0x21
-> 지금 바쁘니 반복 요청 정책 필요
0x78
-> 요청 처리 중이니 기다림 정책 필요
0x22
-> 현재 조건 자체가 맞지 않으니 상태 확인 필요
functional request에서는 ECU별로 다르게 보일 수 있다
Functional Address로 요청을 던지면
ECU마다 조건이 다를 수 있다.
어떤 ECU는 positive response를 주고,
다른 ECU는 0x22를 줄 수 있다.
또 어떤 ECU는 응답하지 않을 수도 있다.
이걸 하나의 결과로 뭉개면 로그가 이상해진다.
SA=0x1001 response=50 03
SA=0x1002 response=7F 10 22
SA=0x1003 no response
Functional request에서는 source address별로 결과를 나눠야 한다.
전체 요청이 실패했다기보다
ECU별 조건이 달랐다고 보는 편이 맞는 경우가 많다.
로그를 이렇게 남기면 빨라진다
0x22는 응답 코드 하나만 남기면 거의 도움이 안 된다.
나는 보통 아래 항목을 같이 남긴다.
- 요청 SID와 sub-function 또는 DID/Routine ID
- SA와 TA
- 현재 테스터가 믿고 있는 session
- 마지막 SessionControl 성공 시각
- 마지막 SecurityAccess 성공 시각과 security level
- 마지막 Tester Present 시각
- ECU 상태 조회 결과가 있다면 power mode 또는 entity status
예를 들면 이런 식이다.
tx sid=0x31 sub=0x01 rid=0x0203 sa=0x0E00 ta=0x1001
ctx session=extended security=level1 last_tp=1800ms ago
rx 7F 31 22
이 정도만 있어도
“패킷이 안 갔나?”보다
“현재 조건 중 무엇이 안 맞나?”로 바로 넘어갈 수 있다.
빠른 체크리스트
7F xx 22가 명확하면 DoIP transport 실패와 먼저 분리- ECU가 실제로 원하는 session에 있는지 다시 확인
- Security Access 이후 재연결, reset, timeout이 끼지 않았는지 확인
- 전원 모드, Entity Status, 서비스별 precondition을 확인
- 긴 작업 뒤에는 이전 요청이 아직 진행 중인지 확인
- functional request라면 SA별로 positive/negative/no response를 분리
함께 보면 좋은 글
- DoIP에서 Session Control 먼저 이해해야 하는 이유
- DoIP Security Access, 여기서부터 ECU 성격이 확 달라진다
- DoIP에서 NRC 0x21이 반복된다: Busy Repeat Request를 timeout처럼 다루면 꼬인다
- DoIP는 붙었는데 진단이 안 된다: Entity Status/Power Mode로 상태부터 확인하기
한 줄 요약
DoIP에서 NRC 0x22가 반복되면 timeout이나 TCP 문제로 단정하지 말고, ECU가 현재 세션/보안/전원/작업 상태 조건을 만족하는지 먼저 확인하는 편이 빠르다.
추천 키워드
DoIP, UDS, NRC 0x22, Conditions Not Correct, Session Control, Tester Present
DevBJ | 오늘을살자, Log Today