임베디드 Linux 게이트웨이에서 특정 CAN ID만 수신하도록 했는데 확장 프레임이나 원격 요청까지 섞이면, ID 비교 마스크에 프레임 종류 비트가 들어 있는지 확인해야 합니다. Linux 커널 SocketCAN 문서의 수신 조건은 (received_can_id & mask) == (filter_can_id & mask)입니다.
CAN ID 정수에는 플래그도 들어 있다
Linux 공개 CAN 헤더는 can_id에 식별자와 프레임 플래그를 함께 담습니다. 표준 식별자는 11비트, 확장 식별자는 29비트입니다. CAN 데이터 바이트에 마스크를 적용하는 기능과는 구분하세요.
| 상수 | 값 | 용도 |
|---|---|---|
| CAN_SFF_MASK | 0x000007FF | 표준 11비트 식별자 |
| CAN_EFF_MASK | 0x1FFFFFFF | 확장 29비트 식별자 |
| CAN_EFF_FLAG | 0x80000000 | 확장 프레임 표시 |
| CAN_RTR_FLAG | 0x40000000 | 원격 요청 프레임 표시 |
| CAN_ERR_FLAG | 0x20000000 | SocketCAN 오류 메시지 표시 |
filter.can_id = 0x123, filter.can_mask = CAN_SFF_MASK만 설정하면 확장 식별자 0x18FF0123도 하위 11비트가 같아서 통과할 수 있습니다. RTR도 마찬가지입니다. 표준 데이터 프레임 0x123만 원한다면 마스크를 CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_SFF_MASK로 정하고 can_id의 EFF·RTR 비트는 0으로 둡니다. 확장 데이터 프레임만 받으려면 can_id에 EFF를 넣고 마스크에는 EFF·RTR·EFF_MASK를 넣습니다. 이 조합은 커널의 필터 최적화 설명에서도 제시합니다.
ID 범위와 여러 필터
표준 데이터 프레임 0x200~0x20F를 받고 싶다면 하위 4비트를 비교에서 제외합니다. can_id = 0x200, can_mask = CAN_EFF_FLAG | CAN_RTR_FLAG | 0x7F0입니다. 0x1FF와 0x210은 거부되고 16개의 표준 데이터 ID가 허용됩니다.
일반적인 CAN_RAW_FILTER 배열은 OR로 결합합니다. 필터 A가 0x123, B가 0x200~0x20F라면 어느 하나와 일치한 프레임을 수신합니다. AND를 원하는 경우의 CAN_RAW_JOIN_FILTERS, 반전 필터의 CAN_INV_FILTER는 이 예제 범위에 포함하지 않습니다. 수신 필터 배열의 길이가 0인 설정은 전부 받기가 아니라 해당 소켓의 수신을 끄는 의미입니다. 오류 메시지는 CAN_RAW_ERR_FILTER로 별도 선택합니다.
C11로 종류·범위 경계를 검증하기
아래 코드는 Windows나 Linux PC에서 실행할 수 있는 비트 비교 모델입니다. 실제 CAN 인터페이스와 커널 소켓을 열지 않습니다. 필터를 정상 데이터/RTR 프레임에 적용하는 논리를 모델링하고 오류 프레임은 별도 경로로 제외합니다. 반전 필터는 지원하지 않습니다. 2,048개 표준 ID 값 각각에 EFF·RTR 플래그 4가지 조합을 적용해 8,192개 입력을 검사합니다. 확장 식별자의 전체 29비트 공간을 전수 검사한 것은 아닙니다.
can_filter.c로 저장하고 gcc -std=c11 -Wall -Wextra -Werror can_filter.c -o can_filter로 빌드합니다. Linux는 ./can_filter, Windows는 ./can_filter.exe로 실행합니다.
검증 출력:
SocketCAN filter: 8192 cases passed; exact=1 range=16
exact=1은 표준 데이터 0x123 하나, range=16은 표준 데이터 0x200~0x20F가 통과했음을 뜻합니다. ID만 비교한 마스크의 EFF·RTR 혼입도 assertion으로 확인합니다.
실제 게이트웨이에 적용하기
Linux 펌웨어에서는 linux/can.h, linux/can/raw.h를 포함하고 struct can_filter를 구성한 뒤 setsockopt(socket_fd, SOL_CAN_RAW, CAN_RAW_FILTER, filters, sizeof filters)로 등록합니다. 반환 값이 -1이면 오류 원인을 확인하고 성공한 것처럼 수신을 계속하지 않습니다. 인터페이스에 bind()하는 코드와 수신 프레임 길이 검사는 별도로 필요합니다.
- 같은 버스에서 표준 데이터 0x123, 다른 ID, 확장 0x18FF0123, RTR 0x123을 각각 보내 기대 수신 여부를 확인합니다.
- 범위 경계 0x1FF·0x200·0x20F·0x210을 확인합니다.
- 필터는 소켓마다 적용됩니다. 다른 모니터 프로그램이 전체 트래픽을 받는 것은 해당 애플리케이션 필터가 실패했다는 뜻이 아닙니다.
- 버스 전체 부하나 CAN 컨트롤러의 하드웨어 수신 부하 감소까지 소켓 필터가 보장하지는 않습니다. CPU 사용량과 드라이버 수신 드롭은 따로 측정합니다.
- 수신이 전혀 없다면 비트레이트·인터페이스 UP·종단 저항·배선·필터 등록 성공 여부를 차례로 확인합니다. 같은 소켓의 자체 송신 수신은 기본 설정에서 꺼져 있다는 점도 확인합니다.
공식 자료 확인: 2026-10-11. 실물 CAN 버스 통신은 수행하지 않았으며, 본문 예제의 필터 계산과 경계를 실제 컴파일·실행해 검증했습니다.
댓글
첫 댓글을 남겨 보세요.