Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: introduce new raw socket option to join the given CAN filters

The CAN_RAW socket can set multiple CAN identifier specific filters that lead
to multiple filters in the af_can.c filter processing. These filters are
indenpendent from each other which leads to logical OR'ed filters when applied.

This socket option joines the given CAN filters in the way that only CAN frames
are passed to user space that matched *all* given CAN filters. The semantic for
the applied filters is therefore changed to a logical AND.

This is useful especially when the filterset is a combination of filters where
the CAN_INV_FILTER flag is set in order to notch single CAN IDs or CAN ID
ranges from the incoming traffic.

As the raw_rcv() function is executed from NET_RX softirq the introduced
variables are implemented as per-CPU variables to avoid extensive locking at
CAN frame reception time.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
a5581ef4 514ac99c

+49 -3
+18 -2
Documentation/networking/can.txt
··· 22 22 4.1.3 RAW socket option CAN_RAW_LOOPBACK 23 23 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS 24 24 4.1.5 RAW socket option CAN_RAW_FD_FRAMES 25 - 4.1.6 RAW socket returned message flags 25 + 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS 26 + 4.1.7 RAW socket returned message flags 26 27 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) 27 28 4.2.1 Broadcast Manager operations 28 29 4.2.2 Broadcast Manager message flags ··· 602 601 CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU. 603 602 The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. 604 603 605 - 4.1.6 RAW socket returned message flags 604 + 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS 605 + 606 + The CAN_RAW socket can set multiple CAN identifier specific filters that 607 + lead to multiple filters in the af_can.c filter processing. These filters 608 + are indenpendent from each other which leads to logical OR'ed filters when 609 + applied (see 4.1.1). 610 + 611 + This socket option joines the given CAN filters in the way that only CAN 612 + frames are passed to user space that matched *all* given CAN filters. The 613 + semantic for the applied filters is therefore changed to a logical AND. 614 + 615 + This is useful especially when the filterset is a combination of filters 616 + where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or 617 + CAN ID ranges from the incoming traffic. 618 + 619 + 4.1.7 RAW socket returned message flags 606 620 607 621 When using recvmsg() call, the msg->msg_flags may contain following flags: 608 622
+1
include/uapi/linux/can/raw.h
··· 57 57 CAN_RAW_LOOPBACK, /* local loopback (default:on) */ 58 58 CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ 59 59 CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ 60 + CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ 60 61 }; 61 62 62 63 #endif /* !_UAPI_CAN_RAW_H */
+30 -1
net/can/raw.c
··· 77 77 struct uniqframe { 78 78 ktime_t tstamp; 79 79 const struct sk_buff *skb; 80 + unsigned int join_rx_count; 80 81 }; 81 82 82 83 struct raw_sock { ··· 88 87 int loopback; 89 88 int recv_own_msgs; 90 89 int fd_frames; 90 + int join_filters; 91 91 int count; /* number of active filters */ 92 92 struct can_filter dfilter; /* default/single filter */ 93 93 struct can_filter *filter; /* pointer to filter(s) */ ··· 134 132 /* eliminate multiple filter matches for the same skb */ 135 133 if (this_cpu_ptr(ro->uniq)->skb == oskb && 136 134 ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) { 137 - return; 135 + if (ro->join_filters) { 136 + this_cpu_inc(ro->uniq->join_rx_count); 137 + /* drop frame until all enabled filters matched */ 138 + if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count) 139 + return; 140 + } else { 141 + return; 142 + } 138 143 } else { 139 144 this_cpu_ptr(ro->uniq)->skb = oskb; 140 145 this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp; 146 + this_cpu_ptr(ro->uniq)->join_rx_count = 1; 147 + /* drop first frame to check all enabled filters? */ 148 + if (ro->join_filters && ro->count > 1) 149 + return; 141 150 } 142 151 143 152 /* clone the given skb to be able to enqueue it into the rcv queue */ ··· 324 311 ro->loopback = 1; 325 312 ro->recv_own_msgs = 0; 326 313 ro->fd_frames = 0; 314 + ro->join_filters = 0; 327 315 328 316 /* alloc_percpu provides zero'ed memory */ 329 317 ro->uniq = alloc_percpu(struct uniqframe); ··· 618 604 619 605 break; 620 606 607 + case CAN_RAW_JOIN_FILTERS: 608 + if (optlen != sizeof(ro->join_filters)) 609 + return -EINVAL; 610 + 611 + if (copy_from_user(&ro->join_filters, optval, optlen)) 612 + return -EFAULT; 613 + 614 + break; 615 + 621 616 default: 622 617 return -ENOPROTOOPT; 623 618 } ··· 689 666 if (len > sizeof(int)) 690 667 len = sizeof(int); 691 668 val = &ro->fd_frames; 669 + break; 670 + 671 + case CAN_RAW_JOIN_FILTERS: 672 + if (len > sizeof(int)) 673 + len = sizeof(int); 674 + val = &ro->join_filters; 692 675 break; 693 676 694 677 default: