我正在尝试按此处所述过滤具有特定ID的CAN帧:https://landlock.io/linux-doc/landlock-v8/networking/can.html#raw-protocol-sockets-with-can-filters-sock-raw
部分代码:
struct can_filter rfilter[4];
if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
fprintf(stderr, "Error while opening socket.\n");
exit(EXIT_FAILURE);
}
rfilter[0].can_id = 0x0D6 | CAN_INV_FILTER;
rfilter[0].can_mask = CAN_SFF_MASK;
rfilter[1].can_id = 0x0D8 | CAN_INV_FILTER;
rfilter[1].can_mask = CAN_SFF_MASK;
rfilter[2].can_id = 0x0E4 | CAN_INV_FILTER;
rfilter[2].can_mask = CAN_SFF_MASK;
rfilter[3].can_id = 0x77F | CAN_INV_FILTER;
rfilter[3].can_mask = CAN_SFF_MASK;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
如果我仅使用四个过滤器之一,并注释掉其他三个过滤器,则该过滤器将按预期工作。如果我全部使用四个过滤器,则根本无法使用。在那种情况下,我仍然可以通过CANbus接口接收所有信息。
所以,我的猜测是我的过滤器以某种方式相互抵消了!要过滤CAN ID 0x0D6、0x0D8、0x0E4和0x77F,我需要更改什么?
答案 0 :(得分:1)
您首先需要提供CAN过滤器:
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
和附加一个整数值,以通过setsockopt()启用CAN_RAW_JOIN_FILTERS
int join_filter = 1;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS, &join_filter, sizeof(join_filter));
顺便说一句。如果为CAN_RAW_JOIN_FILTERS提供了CAN过滤器以将它们设置为setsockopt(),则这是一个意外的长度,应生成-EINVAL作为返回码。
请参阅转储代码: https://github.com/linux-can/can-utils/commit/1a2467ed29302149d4d1253888ac1f1dfcc11d3f
是的,Linux 4.4支持CAN_RAW_JOIN_FILTERS:-)
答案 1 :(得分:0)
像您一样使用CAN_INV_FILTER时,您指定“除ID_x之外的所有内容”。
使用CAN_RAW_FILTER时,它将检查是否存在允许接收的ID通过的规则。就您而言,您的规则相互矛盾,这就是为什么没有过滤任何内容的原因。
4.1.6 RAW套接字选项CAN_RAW_JOIN_FILTERS
CAN_RAW套接字可以设置多个CAN标识符特定的过滤器 在af_can.c过滤器处理中导致多个过滤器。 这些过滤器相互独立,导致 应用时进行逻辑“或”过滤器(请参见4.1.1)。
此套接字选项以仅 将CAN帧传递给与给定CAN all 匹配的用户空间 过滤器。因此更改了所应用过滤器的语义 到逻辑AND。
这在过滤器集是以下各项的组合时特别有用 设置CAN_INV_FILTER标志以进行陷波的过滤器 单个CAN ID或CAN ID范围从传入流量开始。
要获得预期的行为,您应该替换:
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
作者:
setsockopt(s, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS, &rfilter, sizeof(rfilter));
注意:您的Linux内核可能不支持CAN_RAW_JOIN_FILTERS选项