Skip to content

Commit

Permalink
can: replace timestamp as unique skb attribute
Browse files Browse the repository at this point in the history
Commit 514ac99 "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.

Without timestamping to be required by user space applications this timestamp
was not generated which lead to commit 36c0124 "can: fix loss of CAN frames
in raw_rcv" - which forces the timestamp to be set in all CAN related skbuffs
by introducing several __net_timestamp() calls.

This forces e.g. out of tree drivers which are not using alloc_can{,fd}_skb()
to add __net_timestamp() after skbuff creation to prevent the frame loss fixed
in mainline Linux.

This patch removes the timestamp dependency and uses an atomic counter to
create an unique identifier together with the skbuff pointer.

Btw: the new skbcnt element introduced in struct can_skb_priv has to be
initialized with zero in out-of-tree drivers which are not using
alloc_can{,fd}_skb() too.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: linux-stable <stable@vger.kernel.org>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
  • Loading branch information
Oliver Hartkopp authored and Marc Kleine-Budde committed Jul 12, 2015
1 parent 2acb5c3 commit d3b58c4
Show file tree
Hide file tree
Showing 7 changed files with 18 additions and 17 deletions.
7 changes: 2 additions & 5 deletions drivers/net/can/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,6 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
struct can_frame *cf = (struct can_frame *)skb->data;
u8 dlc = cf->can_dlc;

if (!(skb->tstamp.tv64))
__net_timestamp(skb);

netif_rx(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;

Expand Down Expand Up @@ -578,7 +575,6 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
if (unlikely(!skb))
return NULL;

__net_timestamp(skb);
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
Expand All @@ -589,6 +585,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)

can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;

*cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
memset(*cf, 0, sizeof(struct can_frame));
Expand All @@ -607,7 +604,6 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
if (unlikely(!skb))
return NULL;

__net_timestamp(skb);
skb->protocol = htons(ETH_P_CANFD);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
Expand All @@ -618,6 +614,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,

can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;

*cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame));
memset(*cfd, 0, sizeof(struct canfd_frame));
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/can/slcan.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,14 @@ static void slc_bump(struct slcan *sl)
if (!skb)
return;

__net_timestamp(skb);
skb->dev = sl->dev;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;

can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = sl->dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;

memcpy(skb_put(skb, sizeof(struct can_frame)),
&cf, sizeof(struct can_frame));
Expand Down
3 changes: 0 additions & 3 deletions drivers/net/can/vcan.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,6 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY;

if (!(skb->tstamp.tv64))
__net_timestamp(skb);

netif_rx_ni(skb);
}

Expand Down
2 changes: 2 additions & 0 deletions include/linux/can/skb.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
/**
* struct can_skb_priv - private additional data inside CAN sk_buffs
* @ifindex: ifindex of the first interface the CAN frame appeared on
* @skbcnt: atomic counter to have an unique id together with skb pointer
* @cf: align to the following CAN frame at skb->data
*/
struct can_skb_priv {
int ifindex;
int skbcnt;
struct can_frame cf[0];
};

Expand Down
12 changes: 7 additions & 5 deletions net/can/af_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ struct timer_list can_stattimer; /* timer for statistics update */
struct s_stats can_stats; /* packet statistics */
struct s_pstats can_pstats; /* receive list statistics */

static atomic_t skbcounter = ATOMIC_INIT(0);

/*
* af_can socket functions
*/
Expand Down Expand Up @@ -310,12 +312,8 @@ int can_send(struct sk_buff *skb, int loop)
return err;
}

if (newskb) {
if (!(newskb->tstamp.tv64))
__net_timestamp(newskb);

if (newskb)
netif_rx_ni(newskb);
}

/* update statistics */
can_stats.tx_frames++;
Expand Down Expand Up @@ -683,6 +681,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
can_stats.rx_frames++;
can_stats.rx_frames_delta++;

/* create non-zero unique skb identifier together with *skb */
while (!(can_skb_prv(skb)->skbcnt))
can_skb_prv(skb)->skbcnt = atomic_inc_return(&skbcounter);

rcu_read_lock();

/* deliver the packet to sockets listening on all devices */
Expand Down
2 changes: 2 additions & 0 deletions net/can/bcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ static void bcm_can_tx(struct bcm_op *op)

can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;

memcpy(skb_put(skb, CFSIZ), cf, CFSIZ);

Expand Down Expand Up @@ -1217,6 +1218,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
}

can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;
skb->dev = dev;
can_skb_set_owner(skb, sk);
err = can_send(skb, 1); /* send with loopback */
Expand Down
7 changes: 4 additions & 3 deletions net/can/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ MODULE_ALIAS("can-proto-1");
*/

struct uniqframe {
ktime_t tstamp;
int skbcnt;
const struct sk_buff *skb;
unsigned int join_rx_count;
};
Expand Down Expand Up @@ -133,7 +133,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)

/* eliminate multiple filter matches for the same skb */
if (this_cpu_ptr(ro->uniq)->skb == oskb &&
ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) {
this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) {
if (ro->join_filters) {
this_cpu_inc(ro->uniq->join_rx_count);
/* drop frame until all enabled filters matched */
Expand All @@ -144,7 +144,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
}
} else {
this_cpu_ptr(ro->uniq)->skb = oskb;
this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp;
this_cpu_ptr(ro->uniq)->skbcnt = can_skb_prv(oskb)->skbcnt;
this_cpu_ptr(ro->uniq)->join_rx_count = 1;
/* drop first frame to check all enabled filters? */
if (ro->join_filters && ro->count > 1)
Expand Down Expand Up @@ -749,6 +749,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)

can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;

err = memcpy_from_msg(skb_put(skb, size), msg, size);
if (err < 0)
Expand Down

0 comments on commit d3b58c4

Please sign in to comment.