diff options
author | Oliver Hartkopp <socketcan@hartkopp.net> | 2015-06-21 12:50:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-10 12:49:27 -0400 |
commit | 1a2cddd17ebe5e76a796c25e11cdd5518310eabc (patch) | |
tree | b582ac7cd209159054f37f952427cf2264cd5543 | |
parent | aa0b8c72f5c1e0208bfafb383b535bdc9d3b2c6b (diff) |
can: fix loss of CAN frames in raw_rcv
commit 36c01245eb8046c16eee6431e7dbfbb302635fa8 upstream.
As reported by Manfred Schlaegl here
http://marc.info/?l=linux-netdev&m=143482089824232&w=2
commit 514ac99c64b "can: fix multiple delivery of a single CAN frame for
overlapping CAN filters" requires the skb->tstamp to be set to check for
identical CAN skbs.
As net timestamping is influenced by several players (netstamp_needed and
netdev_tstamp_prequeue) Manfred missed a proper timestamp which leads to
CAN frame loss.
As skb timestamping became now mandatory for CAN related skbs this patch
makes sure that received CAN skbs always have a proper timestamp set.
Maybe there's a better solution in the future but this patch fixes the
CAN frame loss so far.
Reported-by: Manfred Schlaegl <manfred.schlaegl@gmx.at>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/net/can/dev.c | 5 | ||||
-rw-r--r-- | drivers/net/can/slcan.c | 1 | ||||
-rw-r--r-- | drivers/net/can/vcan.c | 3 | ||||
-rw-r--r-- | net/can/af_can.c | 6 |
4 files changed, 14 insertions, 1 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index b0f69248cb71..e9b1810d319f 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c | |||
@@ -440,6 +440,9 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx) | |||
440 | struct can_frame *cf = (struct can_frame *)skb->data; | 440 | struct can_frame *cf = (struct can_frame *)skb->data; |
441 | u8 dlc = cf->can_dlc; | 441 | u8 dlc = cf->can_dlc; |
442 | 442 | ||
443 | if (!(skb->tstamp.tv64)) | ||
444 | __net_timestamp(skb); | ||
445 | |||
443 | netif_rx(priv->echo_skb[idx]); | 446 | netif_rx(priv->echo_skb[idx]); |
444 | priv->echo_skb[idx] = NULL; | 447 | priv->echo_skb[idx] = NULL; |
445 | 448 | ||
@@ -575,6 +578,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) | |||
575 | if (unlikely(!skb)) | 578 | if (unlikely(!skb)) |
576 | return NULL; | 579 | return NULL; |
577 | 580 | ||
581 | __net_timestamp(skb); | ||
578 | skb->protocol = htons(ETH_P_CAN); | 582 | skb->protocol = htons(ETH_P_CAN); |
579 | skb->pkt_type = PACKET_BROADCAST; | 583 | skb->pkt_type = PACKET_BROADCAST; |
580 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 584 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -603,6 +607,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, | |||
603 | if (unlikely(!skb)) | 607 | if (unlikely(!skb)) |
604 | return NULL; | 608 | return NULL; |
605 | 609 | ||
610 | __net_timestamp(skb); | ||
606 | skb->protocol = htons(ETH_P_CANFD); | 611 | skb->protocol = htons(ETH_P_CANFD); |
607 | skb->pkt_type = PACKET_BROADCAST; | 612 | skb->pkt_type = PACKET_BROADCAST; |
608 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 613 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index c837eb91d43e..f64f5290d6f8 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c | |||
@@ -207,6 +207,7 @@ static void slc_bump(struct slcan *sl) | |||
207 | if (!skb) | 207 | if (!skb) |
208 | return; | 208 | return; |
209 | 209 | ||
210 | __net_timestamp(skb); | ||
210 | skb->dev = sl->dev; | 211 | skb->dev = sl->dev; |
211 | skb->protocol = htons(ETH_P_CAN); | 212 | skb->protocol = htons(ETH_P_CAN); |
212 | skb->pkt_type = PACKET_BROADCAST; | 213 | skb->pkt_type = PACKET_BROADCAST; |
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 674f367087c5..0ce868de855d 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c | |||
@@ -78,6 +78,9 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev) | |||
78 | skb->dev = dev; | 78 | skb->dev = dev; |
79 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 79 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
80 | 80 | ||
81 | if (!(skb->tstamp.tv64)) | ||
82 | __net_timestamp(skb); | ||
83 | |||
81 | netif_rx_ni(skb); | 84 | netif_rx_ni(skb); |
82 | } | 85 | } |
83 | 86 | ||
diff --git a/net/can/af_can.c b/net/can/af_can.c index 32d710eaf1fc..689c818ed007 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c | |||
@@ -310,8 +310,12 @@ int can_send(struct sk_buff *skb, int loop) | |||
310 | return err; | 310 | return err; |
311 | } | 311 | } |
312 | 312 | ||
313 | if (newskb) | 313 | if (newskb) { |
314 | if (!(newskb->tstamp.tv64)) | ||
315 | __net_timestamp(newskb); | ||
316 | |||
314 | netif_rx_ni(newskb); | 317 | netif_rx_ni(newskb); |
318 | } | ||
315 | 319 | ||
316 | /* update statistics */ | 320 | /* update statistics */ |
317 | can_stats.tx_frames++; | 321 | can_stats.tx_frames++; |