Skip to content
오늘을살자
Go back

DoIP에서 NRC 0x14가 뜬다: Response Too Long을 TCP 문제로 착각하지 말자

Edit page

DoIP로 UDS 요청을 보냈는데 이런 응답이 돌아올 때가 있다.

7F xx 14

처음 보면 조금 이상하다.

DoIP는 TCP 위에서 움직인다.
그래서 큰 응답도 TCP가 알아서 나눠 보내면 되는 것처럼 생각하기 쉽다.

하지만 NRC 0x14 Response Too Long이 명확히 왔다면
대부분은 TCP 조각 문제가 아니라 ECU가 현재 요청에 대한 응답을 만들거나 보내기 어렵다고 판단한 상황이다.

오늘 메모는 DoIP에서 NRC 0x14가 반복될 때 응답 크기와 요청 설계를 어떻게 나눠 봐야 하는지다.

결론부터

0x14는 먼저 이렇게 보는 편이 빠르다.

DoIP framing 문제
-> Generic Header length 파싱 실패, TCP stream reassembly 실패, 무응답

UDS 응답 크기 문제
-> 7F xx 14

7F xx 14가 왔다면 요청은 대체로 ECU 애플리케이션까지 도착했다.
ECU도 요청 SID를 이해했다.

다만 그 요청으로 만들어질 positive response가
현재 ECU 정책이나 내부 버퍼 기준에서 너무 크다고 보는 쪽에 가깝다.

그래서 이때 처음 볼 것은 recv() 크기나 socket timeout이 아니라
요청 하나가 만들 응답 크기다.

흔한 패턴 1: DID를 한 번에 너무 많이 묶는다

ReadDataByIdentifier(0x22)에서 자주 본다.

테스터가 여러 DID를 한 요청에 묶어 보낸다.

22 F1 90 F1 91 F1 92 F1 93 ...

각 DID 응답은 작을 수 있다.
하지만 여러 개를 합치면 ECU가 한 번에 만들 positive response가 커진다.

이때 일부 ECU는 하나씩 읽으면 정상인데,
묶어서 읽으면 7F 22 14를 돌려줄 수 있다.

22 F1 90
-> 62 F1 90 ...

22 F1 90 F1 91 F1 92 F1 93
-> 7F 22 14

이건 DID가 존재하지 않는다는 뜻과 다르다.
그 경우는 0x31 Request Out Of Range 쪽에 더 가깝다.

0x14에서는 먼저 “요청한 항목을 줄이면 되는가”를 확인하는 편이 빠르다.

관련 범위 문제는 DoIP에서 NRC 0x31이 뜬다: DID와 Routine ID 범위를 세션 문제와 나눠 보자와 같이 보면 좋다.

흔한 패턴 2: routine result가 생각보다 크다

RoutineControl(0x31)에서도 비슷한 일이 생긴다.

routine 자체는 시작된다.
그런데 result를 읽는 시점에 응답이 너무 커질 수 있다.

예를 들면 이런 흐름이다.

31 01 02 03
-> routine start accepted

31 03 02 03
-> result request
-> 7F 31 14

테스터 입장에서는 “아까 시작은 됐는데 왜 결과만 안 오지?”처럼 보인다.

이때 routine이 실패한 것인지,
결과 payload가 큰 것인지,
결과를 나눠 읽는 별도 옵션이 있는지 분리해야 한다.

로그에는 routine ID만 남기지 말고
result 요청의 option record와 예상 응답 크기를 같이 남기는 편이 좋다.

흔한 패턴 3: Ethernet이라도 ECU 내부 버퍼는 무한하지 않다

DoIP를 처음 붙이면 이런 착각을 하기 쉽다.

CAN보다 Ethernet이 빠르다
-> 큰 진단 응답도 그냥 한 번에 받으면 된다

하지만 ECU 애플리케이션, 진단 미들웨어, gateway 내부 버퍼는 별개다.
TCP가 stream을 나눠 보내 줄 수 있어도,
ECU가 UDS positive response를 만들기 전에 내부에 담아야 하는 구조라면 한계가 생긴다.

그래서 DoIP에서는 아래를 분리해서 봐야 한다.

전송 매체가 큰 데이터를 나눠 보낼 수 있는가
-> TCP와 DoIP framing 문제

ECU가 한 UDS 응답을 만들 수 있는가
-> UDS 서비스 정책과 내부 버퍼 문제

0x14는 보통 두 번째 쪽에서 출발한다.

DoIP가 TCP stream이라는 점은 DoIP는 TCP stream이다: recv()만 믿고 파싱하면 깨지는 이유에서 따로 이어진다.

흔한 패턴 4: 0x13이나 0x78과 섞어서 본다

0x140x13, 0x78과 헷갈리기 쉽다.

셋 다 “응답이 원하는 모양으로 안 나온다”처럼 보이기 때문이다.

하지만 출발점은 다르다.

0x13
-> 요청 형식이나 길이가 맞지 않음

0x14
-> 요청은 읽었지만 positive response가 너무 큼

0x78
-> 처리 중이니 더 기다려야 함

0x14에 같은 요청을 그대로 retry하면 보통 해결되지 않는다.
ECU가 바쁘다는 의미가 아니라
그 요청 모양으로는 응답이 너무 크다는 의미에 가깝기 때문이다.

그래서 retry 정책보다 요청 분할 정책이 먼저다.

길이 오류 쪽은 DoIP에서 NRC 0x13이 뜬다: 메시지 길이 오류를 TCP 조각 문제로 착각하지 말자와 연결된다.

요청을 줄이는 기준을 코드에 둔다

0x14를 한 번 만난 뒤 사람이 수동으로 DID를 줄이면
다음에 같은 문제가 또 난다.

테스터 쪽에 서비스별 분할 기준을 둬야 한다.

예를 들면 이런 식이다.

ReadDataByIdentifier
-> 한 요청에 넣을 DID 개수 제한
-> 큰 DID는 단독 요청으로 분리

RoutineControl result
-> result option record로 범위를 좁힐 수 있는지 확인
-> 불가능하면 timeout이 아니라 response-size failure로 기록

Transfer 관련 서비스
-> block size, maxNumberOfBlockLength, ECU 정책을 따로 기록

핵심은 “큰 응답을 받기 위해 socket buffer만 키운다”가 아니다.
요청 하나가 만드는 UDS 응답 크기를 제어해야 한다.

로그를 이렇게 남기면 빨라진다

0x14는 응답 코드만 찍으면 별 도움이 안 된다.

나는 보통 아래 항목을 같이 남긴다.

  1. 원 요청 SID
  2. DID 개수 또는 Routine ID
  3. 요청 payload 길이
  4. 예상 positive response 길이
  5. SA와 TA
  6. physical request인지 functional request인지
  7. 같은 요청을 줄였을 때 성공하는지

예를 들면 이런 식이다.

tx sid=0x22 did_count=8 req_len=17 sa=0x0E00 ta=0x1001
expect positive_len ~= sum(did_payload)
rx 7F 22 14
action split_did_request

이 정도만 있어도
“TCP가 중간에 잘렸나?”보다
“한 요청에 너무 많이 넣었나?”로 바로 넘어갈 수 있다.

빠른 체크리스트

  1. 7F xx 14가 명확하면 TCP stream 파싱 실패와 먼저 분리
  2. 한 요청이 만들 positive response 크기를 추정
  3. 여러 DID를 묶었다면 하나씩 또는 작은 묶음으로 나눠 재확인
  4. Routine result나 DTC 계열처럼 응답이 커질 수 있는 서비스를 따로 표시
  5. 같은 요청을 그대로 retry하지 말고 요청 분할 정책을 적용
  6. 0x13, 0x14, 0x78, 0x31을 같은 실패로 뭉개지 않는지 확인

함께 보면 좋은 글

한 줄 요약

DoIP에서 NRC 0x14가 반복되면 TCP buffer나 timeout보다 먼저, 요청 하나가 만드는 UDS positive response가 ECU가 감당할 수 있는 크기인지 확인하는 편이 빠르다.

추천 키워드

DoIP, UDS, NRC 0x14, Response Too Long, ReadDataByIdentifier, Diagnostic Message


DevBJ | 오늘을살자, Log Today


Edit page
Share this post on:

Previous Post
lwIP에서 tcp_write()가 ERR_MEM을 돌려준다: free RAM보다 snd_buf와 snd_queuelen을 먼저 보자
Next Post
오늘의 테크 뉴스: SDV Provenance, Edge AI 플랫폼, 장기 보안 업데이트 (2026-06-29)