SocketCAN:过滤具有某些 CAN ID 的帧不起作用

ci7*_*en4 6 c can-bus socketcan

我正在尝试过滤具有某些 ID 的 CAN 帧,如下所述:https: //landlock.io/linux-doc/landlock-v8/networking/can.html#raw-protocol-sockets-with-can-filters-sock -生的

我的部分代码:

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));
Run Code Online (Sandbox Code Playgroud)

如果我只使用四个过滤器之一并注释掉其他三个,它就会按预期工作。如果我使用所有四个过滤器,它根本不起作用。在这种情况下,我仍然可以接收 CANbus 接口上的所有内容。

所以,我的猜测是我的过滤器以某种方式相互抵消了?!我需要更改什么才能过滤 CAN ID 0x0D6、0x0D8、0x0E4 和 0x77F?

小智 7

当像您一样使用 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 过滤器匹配的用户空间的方式连接给定CAN 过滤器。因此,所应用过滤器的语义更改为逻辑 AND。

当过滤器集是过滤器组合(其中设置了 CAN_INV_FILTER 标志以便从传入流量中切出单个 CAN ID 或 CAN ID 范围)时,这尤其有用。

为了获得预期的行为,您应该替换:

setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
Run Code Online (Sandbox Code Playgroud)

经过:

setsockopt(s, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS, &rfilter, sizeof(rfilter));
Run Code Online (Sandbox Code Playgroud)

注意:您的 Linux 内核可能不支持 CAN_RAW_JOIN_FILTERS 选项