Skip to content

실습 목표#

  • DoIP 예제를 실행하고 라우팅 활성화부터 진단 응답까지의 흐름을 확인한다.
  • 진단 요청과 응답 프레임을 바이트 단위로 나눠 읽는다.
  • 서버 코드의 빈칸을 채워 라우팅 활성화 허용과 거부, VIN을 직접 구현한다.


실습. DoIP 예제 코드 실행#

실습 환경 세팅#

다음 스크립트를 라즈베리파이 터미널과 WSL에 각각 입력하여 DoIP 실습 환경을 세팅한다.

라즈베리파이·터미널
make
./ecu_server

노트북·WSL
make
./tester_client


WireShark 캡처 분석#

WireShark에서 필터를 ‘tcp.port==13400'으로 설정한다.

이미지

같은 DoIP 프레임이라도 표시되는 이름이 다른 것을 확인할 수 있다. 이는 WireShark에서 DoIP 안에 UDS가 들어 있으면 구체적으로 UDS라고 표시해주기 때문이다.


Routing Activation Request 분석#

다음 표를 참고하여 Routing activation 요청을 분석한다.

02 FD 00 05 00 00 00 07 0E 00 00 00 00 00 00
오프셋 바이트 필드 의미
0 ~ 1 02 FD Version / Inverse 0x02와 그 반전 값, 오류 검출용
2 ~ 3 00 05 Payload Type 라우팅 활성화 요청
4 ~ 7 00 00 00 07 Payload Length 7 bytes
8 ~ 9 0E 00 Source Address 테스터의 논리 주소
10 00 Activation Type 기본 활성화
11 ~ 14 00 00 00 00 Reserved -


Routing Activation Response 분석#

다음 표를 참고하여 Routing activation 응답을 분석한다.

02 FD 00 06 00 00 00 09 0E 00 00 01 10 00 00 00 00
오프셋 바이트 필드 의미
0 ~ 1 02 FD Version / Inverse 0x02와 그 반전 값, 오류 검출용
2 ~ 3 00 06 Payload Type 라우팅 활성화 응답
4 ~ 7 00 00 00 09 Payload Length 9 bytes
8 ~ 9 0E 00 Tester Address 요청한 테스터 주소를 그대로 돌려줌
10 ~ 11 00 01 ECU Address 응답하는 ECU의 논리 주소
12 10 Response Code 0x10, 활성화 성공
13 ~ 16 00 00 00 00 Reserved -


진단 요청 프레임 분석#

다음 표를 참고하여 진단 요청 프레임을 분석한다.

02 FD 80 01 00 00 00 07 0E 00 00 01 22 F1 90
오프셋 바이트 필드 의미
0 ~ 1 02 FD Version / Inverse 0x02와 그 반전 값, 오류 검출용
2 ~ 3 80 01 Payload Type 라우팅 활성화 응답
4 ~ 7 00 00 00 07 Payload Length 7 Bytes, 주소 4 + UDS 3
8 ~ 9 0E 00 Source Address 테스터의 논리 주소
10 ~ 11 00 01 Target Address ECU의 논리 주소
12 ~ 14 22 F1 90 UDS 식별자 F190 읽기 요청


진단 응답 프레임 분석#

다음 표를 참고하여 진단 응답 프레임을 분석한다.

02 FD 80 01 00 00 00 18 00 01 0E 00 62 F1 90 54
45 53 54 56 49 4E 30 31 32 33 34 35 36 37 38 39
오프셋 바이트 필드 의미
0 ~ 1 02 FD Version / Inverse 0x02와 그 반전 값, 오류 검출용
2 ~ 3 80 01 Payload Type 진단 메시지
4 ~ 7 00 00 00 18 Payload Length 24 Bytes, 주소 4 + UDS 3 + VIN 17
8 ~ 9 00 01 Source Address ECU의 논리 주소
10 ~ 11 0E 00 Target Address 테스터의 논리 주소
12 ~ 14 62 F1 90 UDS 긍정 응답, 요청 22에 0x40을 더한 값
15 ~ 31 54 45 53 54 ⋯ 38 39 VIN TESTVIN0123456789


테스터 주소 대역 분석#

Routing Activation Request에는 테스터의 논리 주소가 들어 있다. 이 때 ECU는 그 주소가 외부 진단기 대역인지 보고 허용할지 거부할지 정한다.

다음 표를 참고하여 주소에 따른 ECU의 허용/거부 여부를 진단할 수 있다.

대역 용도 허용/거부 여부
0x0001 ~ 0x0DFF ECU 등 차량 내부 장치 거부
0x0E00 ~ 0x0FFF 외부 진단기 전용 허용
0x1000 ~ 0x7FFF 제조사가 정하는 범위 제조사에 따라 상이
0x8000 ~ 0xCFFF 표준이 예약해 둔 범위 거부


ECU가 해당 주소를 거부하는 사유는 여러 가지이다. 이번 실습에서는 성공(0x10)과 주소 거부(0x00) 두 가지만 다룬다.

다음 표를 참고하여 거부 사유를 확인한다.

코드 의미
0x00 알 수 없는 소스 주소 · 유효 대역 밖
0x01 이 소스 주소가 이미 다른 소켓에서 활성화됨
0x02 소스 주소가 이미 다른 곳에 등록됨
0x03 소켓 자원 부족 · 동시 연결 초과
0x04 인증 없이 활성화를 시도함
0x05 차량이 활성화를 거부함
0x06 지원하지 않는 활성화 타입
0x07 보안 연결(TLS)이 필요함
0x10 성공 · 활성화됨
0x11 성공했으나 추가 확인이 필요함


과제 1. 라우팅 활성화 허용과 거부#

방금 실습한 스크립트는 주소를 보지 않고 무조건 활성화시키는 단순 버전이다. 이번에는 ECU가 주소를 보고 허용/거부를 판단할 수 있게 테스터 주소를 검사하는 세 자리를 채운다.

ecu_server_blank.cpp
uint16_t tester = (buf[8] << 8) | buf[9];
uint8_t  code;
if ( /* 빈칸 1a */ ) {
    /* 빈칸 1b */
    printf("routing activation OK (tester=0x%04X)\n", tester);
} else {
    /* 빈칸 1c */
    printf("routing activation REJECTED (tester=0x%04X)\n", tester);
}
라즈베리파이·터미널
make
./ecu_server_blank


라우팅 활성화 허용과 거부#

테스터 주소가 외부 진단기 대역 안이라면 성공 코드 0x10, 밖이라면 거부 코드 0x00이 표시되도록 설정한다.

ecu_server_blank.cpp
if (tester >= 0x0E00 && tester <= 0x0FFF) {
    code = 0x10; activated = true;
} else {
    code = 0x00;
}
노트북
./tester_client 0x0E00
./tester_client 0x8000

관찰 포인트

0x0E00은 활성화 성공 뒤 VIN 응답을, 0x8000은 거부 코드(0x00)를 받고 멈추면 정답이다.


과제 2. VIN 직접 만들기#

VIN은 차 한 대를 식별하는 17자리 코드로, 자리마다 뜻이 정해져 있다. 실습 서버는 임의의 값을 사용하지만 실제로는 아래 표의 규칙을 따른다.

자리 의미 값의 예
1 제조 국가 K 한국 · J 일본 · W 독일
2 제조사 M 현대 · L 기아 · B BMW · D 벤츠
3 차량 형태 H 승용 · J 승합 · F 화물
4 ~ 6 차종과 세부 차종, 차체 형상 모델별로 정해진 코드
7 안전장치 1 없음 · 4 에어백
8 배기량 A 1800cc · D 3300cc
9 보안 코드 P 좌핸들 · R 우핸들
10 제조 연도 M 2021 · P 2023 · T 2026
11 생산 공장 A 아산 · C 전주 · U 울산
12 ~ 17 생산 번호 여섯 자리 일련번호


이제 위의 표를 보고 자기만의 17자리를 만들어 서버 코드에 넣어본다. 한 글자라도 모자라거나 넘으면 Payload Length가 달라지기 때문에 반드시 17글자여야 한다. "_"안에 입력하여 실행해보자.

ecu_server_blank.cpp
const char* vin = "_________________";
라즈베리파이
make
./ecu_server_blank

관찰 포인트

테스터 출력과 캡처의 ASCII 창에서 바뀐 값이 보이면 성공이다. Length는 17글자라면 0x18 그대로 출력된다.


VIN 예시#

현대 승용차, 좌핸들, 2026년 제조, 울산 공장, 42번째 생산분으로 구성한 예는 다음과 같다.

ecu_server_blank.cpp
const char* vin = "KMHMA14TPTU000042";

관찰 포인트

응답의 hex의 ASCII 부분이 바뀌고 길이값이 그대로인지 확인해 본다.


긍정 응답과 부정 응답#

서버가 요청을 처리할 수 있으면 긍정, 못 하면 부정으로 응답한다. 부정 응답은 7F로 시작하여 요청 SID와 거부 사유가 붙는다.

아래 스크립트를 입력하여 응답을 확인해본다.

라즈베리파이
./ecu_server_blank
노트북·WSL
./tester_client 0x0E00
./tester_client 0x0E00 11 01 00


예시 응답
02 FD 80 01 00 00 00 07 00 01 0E 00 7F 11 11
해당 응답의 '7F'를 통해 이 응답이 부정 응답임을 알 수 있다.