diff options
-rw-r--r-- | Documentation/networking/can.txt | 20 | ||||
-rw-r--r-- | include/uapi/linux/can/raw.h | 1 | ||||
-rw-r--r-- | net/can/raw.c | 31 |
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"); | |||
77 | struct uniqframe { | 77 | struct 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 | ||
82 | struct raw_sock { | 83 | struct 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 | } |