В Python я пытаюсь использовать фильтрацию J1939, как указано в документации ядра Linux: https://www.kernel.org/doc/html/latest/networking/j1939.html
Следующий код не работает в строке setsockopt() (настройка фильтров):
import socket
import struct
def pack_J1939_filters(can_filters):
can_filter_fmt = "=" + "2Q2B2I" * len(can_filters)
filter_data = []
for can_filter in can_filters:
name = can_filter['name']
name_mask = can_filter['name_mask']
addr = can_filter['addr']
addr_mask = can_filter['addr_mask']
pgn = can_filter['pgn']
pgn_mask = can_filter['pgn_mask']
filter_data.append(name)
filter_data.append(name_mask)
filter_data.append(addr)
filter_data.append(addr_mask)
filter_data.append(pgn)
filter_data.append(pgn_mask)
return struct.pack(can_filter_fmt, *filter_data)
s = socket.socket(socket.PF_CAN, socket.SOCK_DGRAM, socket.CAN_J1939)
interface = "vcan0"
src_name = socket.J1939_NO_NAME
src_pgn = socket.J1939_NO_PGN
src_addr = 0x81
src_sck_addr = (interface, src_name, src_pgn, src_addr)
s.bind(src_sck_addr)
filters = [{"name": 0, "name_mask":0, "addr":0, "addr_mask":0, "pgn": 0, "pgn_mask": 0}]
packed_filters = pack_J1939_filters(filters)
# socket.SOL_CAN_J1939 does not seem to exist
SOL_CAN_BASE = 100
CAN_J1939 = 7
SOL_CAN_J1939 = SOL_CAN_BASE + CAN_J1939
s.setsockopt(SOL_CAN_J1939, socket.SO_J1939_FILTER , packed_filters)
s.recvfrom(128)
s.close()
Во-первых, в документации ядра упоминается использование SOL_CAN_J1939 в качестве первого аргумента. Однако socket.SOL_CAN_J1939 не существует в пакете сокетов. Итак, глядя на код в этом месте, я смог понять, что это значение int должно быть 107: http://socket-can.996257.n3.nabble.com/RFC-v3-0-6-CAN-add-SAE-J1939-protocol-td7571.html
Что касается третьего аргумента setsockopt(), я упаковал фильтры в соответствии со структурой j1939_filter (26 байт, как описано в коде из предыдущей ссылки). Это похоже на то, что делается в can.interfaces.socketcan.utils для необработанного CAN.
Что я делаю неправильно, чтобы вызвать сбой setsockopt()?