aboutsummaryrefslogtreecommitdiffstats
path: root/net/can/raw.c
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2015-04-01 01:50:29 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2015-04-01 05:28:22 -0400
commita5581ef4c2eac6449188862e903eb46c7233582a (patch)
treeb334b1858d3bffe49af1fb95650cb5affb7e1510 /net/can/raw.c
parent514ac99c64b22d83b52dfee3b8becaa69a92bc4a (diff)
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>
Diffstat (limited to 'net/can/raw.c')
-rw-r--r--net/can/raw.c31
1 files changed, 30 insertions, 1 deletions
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 }