diff options
| author | Oliver Hartkopp <socketcan@hartkopp.net> | 2015-04-01 01:50:28 -0400 |
|---|---|---|
| committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2015-04-01 05:27:41 -0400 |
| commit | 514ac99c64b22d83b52dfee3b8becaa69a92bc4a (patch) | |
| tree | dc44e61b13c9c7279ad7b5be1195f5cebeb422c2 | |
| parent | a0bc163a7cf2ceb413a76cfd7149c6591db829ea (diff) | |
can: fix multiple delivery of a single CAN frame for overlapping 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 patch makes sure that every CAN frame which is filtered for a specific
socket is only delivered once to the user space. This is independent from the
number of matching CAN filters of this socket.
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>
| -rw-r--r-- | net/can/raw.c | 21 |
1 files changed, 21 insertions, 0 deletions
diff --git a/net/can/raw.c b/net/can/raw.c index 63ffdb0f3a23..0c8d537b59b8 100644 --- a/net/can/raw.c +++ b/net/can/raw.c | |||
| @@ -74,6 +74,11 @@ MODULE_ALIAS("can-proto-1"); | |||
| 74 | * storing the single filter in dfilter, to avoid using dynamic memory. | 74 | * storing the single filter in dfilter, to avoid using dynamic memory. |
| 75 | */ | 75 | */ |
| 76 | 76 | ||
| 77 | struct uniqframe { | ||
| 78 | ktime_t tstamp; | ||
| 79 | const struct sk_buff *skb; | ||
| 80 | }; | ||
| 81 | |||
| 77 | struct raw_sock { | 82 | struct raw_sock { |
| 78 | struct sock sk; | 83 | struct sock sk; |
| 79 | int bound; | 84 | int bound; |
| @@ -86,6 +91,7 @@ struct raw_sock { | |||
| 86 | struct can_filter dfilter; /* default/single filter */ | 91 | struct can_filter dfilter; /* default/single filter */ |
| 87 | struct can_filter *filter; /* pointer to filter(s) */ | 92 | struct can_filter *filter; /* pointer to filter(s) */ |
| 88 | can_err_mask_t err_mask; | 93 | can_err_mask_t err_mask; |
| 94 | struct uniqframe __percpu *uniq; | ||
| 89 | }; | 95 | }; |
| 90 | 96 | ||
| 91 | /* | 97 | /* |
| @@ -123,6 +129,15 @@ static void raw_rcv(struct sk_buff *oskb, void *data) | |||
| 123 | if (!ro->fd_frames && oskb->len != CAN_MTU) | 129 | if (!ro->fd_frames && oskb->len != CAN_MTU) |
| 124 | return; | 130 | return; |
| 125 | 131 | ||
| 132 | /* eliminate multiple filter matches for the same skb */ | ||
| 133 | if (this_cpu_ptr(ro->uniq)->skb == oskb && | ||
| 134 | ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) { | ||
| 135 | return; | ||
| 136 | } else { | ||
| 137 | this_cpu_ptr(ro->uniq)->skb = oskb; | ||
| 138 | this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp; | ||
| 139 | } | ||
| 140 | |||
| 126 | /* clone the given skb to be able to enqueue it into the rcv queue */ | 141 | /* clone the given skb to be able to enqueue it into the rcv queue */ |
| 127 | skb = skb_clone(oskb, GFP_ATOMIC); | 142 | skb = skb_clone(oskb, GFP_ATOMIC); |
| 128 | if (!skb) | 143 | if (!skb) |
| @@ -297,6 +312,11 @@ static int raw_init(struct sock *sk) | |||
| 297 | ro->recv_own_msgs = 0; | 312 | ro->recv_own_msgs = 0; |
| 298 | ro->fd_frames = 0; | 313 | ro->fd_frames = 0; |
| 299 | 314 | ||
| 315 | /* alloc_percpu provides zero'ed memory */ | ||
| 316 | ro->uniq = alloc_percpu(struct uniqframe); | ||
| 317 | if (unlikely(!ro->uniq)) | ||
| 318 | return -ENOMEM; | ||
| 319 | |||
| 300 | /* set notifier */ | 320 | /* set notifier */ |
| 301 | ro->notifier.notifier_call = raw_notifier; | 321 | ro->notifier.notifier_call = raw_notifier; |
| 302 | 322 | ||
| @@ -339,6 +359,7 @@ static int raw_release(struct socket *sock) | |||
| 339 | ro->ifindex = 0; | 359 | ro->ifindex = 0; |
| 340 | ro->bound = 0; | 360 | ro->bound = 0; |
| 341 | ro->count = 0; | 361 | ro->count = 0; |
| 362 | free_percpu(ro->uniq); | ||
| 342 | 363 | ||
| 343 | sock_orphan(sk); | 364 | sock_orphan(sk); |
| 344 | sock->sk = NULL; | 365 | sock->sk = NULL; |
