aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/can.txt20
-rw-r--r--include/uapi/linux/can/raw.h1
-rw-r--r--net/can/raw.c31
3 files changed, 49 insertions, 3 deletions
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index 0a2859a8ee7e..5abad1e921ca 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -22,7 +22,8 @@ This file contains
22 4.1.3 RAW socket option CAN_RAW_LOOPBACK 22 4.1.3 RAW socket option CAN_RAW_LOOPBACK
23 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS 23 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS
24 4.1.5 RAW socket option CAN_RAW_FD_FRAMES 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 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) 27 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
27 4.2.1 Broadcast Manager operations 28 4.2.1 Broadcast Manager operations
28 4.2.2 Broadcast Manager message flags 29 4.2.2 Broadcast Manager message flags
@@ -601,7 +602,22 @@ solution for a couple of reasons:
601 CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU. 602 CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU.
602 The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. 603 The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall.
603 604
604 4.1.6 RAW socket returned message flags 605 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS
606
607 The CAN_RAW socket can set multiple CAN identifier specific filters that
608 lead to multiple filters in the af_can.c filter processing. These filters
609 are indenpendent from each other which leads to logical OR'ed filters when
610 applied (see 4.1.1).
611
612 This socket option joines the given CAN filters in the way that only CAN
613 frames are passed to user space that matched *all* given CAN filters. The
614 semantic for the applied filters is therefore changed to a logical AND.
615
616 This is useful especially when the filterset is a combination of filters
617 where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or
618 CAN ID ranges from the incoming traffic.
619
620 4.1.7 RAW socket returned message flags
605 621
606 When using recvmsg() call, the msg->msg_flags may contain following flags: 622 When using recvmsg() call, the msg->msg_flags may contain following flags:
607 623
diff --git a/include/uapi/linux/can/raw.h b/include/uapi/linux/can/raw.h
index 78ec76fd89a6..8735f1080385 100644
--- a/include/uapi/linux/can/raw.h
+++ b/include/uapi/linux/can/raw.h
@@ -57,6 +57,7 @@ enum {
57 CAN_RAW_LOOPBACK, /* local loopback (default:on) */ 57 CAN_RAW_LOOPBACK, /* local loopback (default:on) */
58 CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ 58 CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */
59 CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ 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#endif /* !_UAPI_CAN_RAW_H */ 63#endif /* !_UAPI_CAN_RAW_H */
diff --git a/net/can/raw.c b/net/can/raw.c
index 0c8d537b59b8..31b9748cbb4e 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -77,6 +77,7 @@ MODULE_ALIAS("can-proto-1");
77struct uniqframe { 77struct uniqframe {
78 ktime_t tstamp; 78 ktime_t tstamp;
79 const struct sk_buff *skb; 79 const struct sk_buff *skb;
80 unsigned int join_rx_count;
80}; 81};
81 82
82struct raw_sock { 83struct raw_sock {
@@ -87,6 +88,7 @@ struct raw_sock {
87 int loopback; 88 int loopback;
88 int recv_own_msgs; 89 int recv_own_msgs;
89 int fd_frames; 90 int fd_frames;
91 int join_filters;
90 int count; /* number of active filters */ 92 int count; /* number of active filters */
91 struct can_filter dfilter; /* default/single filter */ 93 struct can_filter dfilter; /* default/single filter */
92 struct can_filter *filter; /* pointer to filter(s) */ 94 struct can_filter *filter; /* pointer to filter(s) */
@@ -132,10 +134,21 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
132 /* eliminate multiple filter matches for the same skb */ 134 /* eliminate multiple filter matches for the same skb */
133 if (this_cpu_ptr(ro->uniq)->skb == oskb && 135 if (this_cpu_ptr(ro->uniq)->skb == oskb &&
134 ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) { 136 ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) {
135 return; 137 if (ro->join_filters) {
138 this_cpu_inc(ro->uniq->join_rx_count);
139 /* drop frame until all enabled filters matched */
140 if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count)
141 return;
142 } else {
143 return;
144 }
136 } else { 145 } else {
137 this_cpu_ptr(ro->uniq)->skb = oskb; 146 this_cpu_ptr(ro->uniq)->skb = oskb;
138 this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp; 147 this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp;
148 this_cpu_ptr(ro->uniq)->join_rx_count = 1;
149 /* drop first frame to check all enabled filters? */
150 if (ro->join_filters && ro->count > 1)
151 return;
139 } 152 }
140 153
141 /* clone the given skb to be able to enqueue it into the rcv queue */ 154 /* clone the given skb to be able to enqueue it into the rcv queue */
@@ -311,6 +324,7 @@ static int raw_init(struct sock *sk)
311 ro->loopback = 1; 324 ro->loopback = 1;
312 ro->recv_own_msgs = 0; 325 ro->recv_own_msgs = 0;
313 ro->fd_frames = 0; 326 ro->fd_frames = 0;
327 ro->join_filters = 0;
314 328
315 /* alloc_percpu provides zero'ed memory */ 329 /* alloc_percpu provides zero'ed memory */
316 ro->uniq = alloc_percpu(struct uniqframe); 330 ro->uniq = alloc_percpu(struct uniqframe);
@@ -604,6 +618,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
604 618
605 break; 619 break;
606 620
621 case CAN_RAW_JOIN_FILTERS:
622 if (optlen != sizeof(ro->join_filters))
623 return -EINVAL;
624
625 if (copy_from_user(&ro->join_filters, optval, optlen))
626 return -EFAULT;
627
628 break;
629
607 default: 630 default:
608 return -ENOPROTOOPT; 631 return -ENOPROTOOPT;
609 } 632 }
@@ -668,6 +691,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
668 val = &ro->fd_frames; 691 val = &ro->fd_frames;
669 break; 692 break;
670 693
694 case CAN_RAW_JOIN_FILTERS:
695 if (len > sizeof(int))
696 len = sizeof(int);
697 val = &ro->join_filters;
698 break;
699
671 default: 700 default:
672 return -ENOPROTOOPT; 701 return -ENOPROTOOPT;
673 } 702 }