Skip to contentSkip to conversation

CAN FD support part 1 - uncommented source

RFC In review Oliver Hartkopp 4 participants 11 messages May 3, 2012

Subsystems (3)
lore
Share & tools
lore

Oliver Hartkopp

author maintainer
#0 lore raw

RFC 1/1 CAN FD support part 1 - uncommented source

drivers/net/can/dev.c +1 -1
index f03d7a4..1b7e843 100644
@@ -454,7 +454,7 @@ EXPORT_SYMBOL_GPL(can_bus_off);
 static void can_setup(struct net_device *dev)
 {
 	dev->type = ARPHRD_CAN;
-	dev->mtu = sizeof(struct can_frame);
+	dev->mtu = CAN_MTU;
 	dev->hard_header_len = 0;
 	dev->addr_len = 0;
 	dev->tx_queue_len = 10;
drivers/net/can/vcan.c +15 -5
index ea2d942..bddbafb 100644
@@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 
 	stats->rx_packets++;
-	stats->rx_bytes += cf->can_dlc;
+	stats->rx_bytes += can_dlc2len(cf->can_dlc);
 
-	skb->protocol  = htons(ETH_P_CAN);
 	skb->pkt_type  = PACKET_BROADCAST;
 	skb->dev       = dev;
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -94,7 +93,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 		return NETDEV_TX_OK;
 
 	stats->tx_packets++;
-	stats->tx_bytes += cf->can_dlc;
+	stats->tx_bytes += can_dlc2len(cf->can_dlc);
 
 	/* set flag whether this packet has to be looped back */
 	loop = skb->pkt_type == PACKET_LOOPBACK;
@@ -108,7 +107,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 			 * CAN core already did the echo for us
 			 */
 			stats->rx_packets++;
-			stats->rx_bytes += cf->can_dlc;
+			stats->rx_bytes += can_dlc2len(cf->can_dlc);
 		}
 		kfree_skb(skb);
 		return NETDEV_TX_OK;
@@ -133,14 +132,25 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 	return NETDEV_TX_OK;
 }
 
+static int vcan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if (new_mtu == CAN_MTU || new_mtu == CANFD_MTU) {
+		dev->mtu = new_mtu;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static const struct net_device_ops vcan_netdev_ops = {
 	.ndo_start_xmit = vcan_tx,
+	.ndo_change_mtu = vcan_change_mtu,
 };
 
 static void vcan_setup(struct net_device *dev)
 {
 	dev->type		= ARPHRD_CAN;
-	dev->mtu		= sizeof(struct can_frame);
+	dev->mtu		= CAN_MTU;
 	dev->hard_header_len	= 0;
 	dev->addr_len		= 0;
 	dev->tx_queue_len	= 0;
include/linux/can.h +62 -0

74 lines not on this page · raw message

include/linux/can/core.h +2 -2
index 0ccc1cd..e6a3126 100644
@@ -17,10 +17,10 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 
-#define CAN_VERSION "20090105"
+#define CAN_VERSION "20120413"
 
 /* increment this number each time you change some user-space interface */
-#define CAN_ABI_VERSION "8"
+#define CAN_ABI_VERSION "9"
 
 #define CAN_VERSION_STRING "rev " CAN_VERSION " abi " CAN_ABI_VERSION
 
include/linux/can/dev.h +20 -6
index 5d2efe7..082b664 100644
@@ -61,7 +61,11 @@ struct can_priv {
  * To be used in the CAN netdriver receive path to ensure conformance with
  * ISO 11898-1 Chapter 8.4.2.3 (DLC field)
  */
-#define get_can_dlc(i)	(min_t(__u8, (i), 8))
+#define get_can_dlc(i)		(min_t(__u8, (i), CAN_MAX_DLC))
+#define get_canfd_dlc(i)	(min_t(__u8, (i), CANFD_MAX_DLC))
+
+#define CAN_MTU		(sizeof(struct can_frame))
+#define CANFD_MTU	(sizeof(struct canfd_frame))
 
 /* Drop a given socketbuffer if it does not contain a valid CAN frame. */
 static inline int can_dropped_invalid_skb(struct net_device *dev,
@@ -69,13 +73,23 @@ static inline int can_dropped_invalid_skb(struct net_device *dev,
 {
 	const struct can_frame *cf = (struct can_frame *)skb->data;
 
-	if (unlikely(skb->len != sizeof(*cf) || cf->can_dlc > 8)) {
-		kfree_skb(skb);
-		dev->stats.tx_dropped++;
-		return 1;
-	}
+	if (skb->protocol == htons(ETH_P_CAN)) {
+		if (skb->len != sizeof(struct can_frame) ||
+		    cf->can_dlc > CAN_MAX_DLC)
+			goto inval_skb;
+	} else if (skb->protocol == htons(ETH_P_CANFD)) {
+		if (skb->len != sizeof(struct canfd_frame) ||
+		    cf->can_dlc > CANFD_MAX_DLC)
+			goto inval_skb;
+	} else
+		goto inval_skb;
 
 	return 0;
+
+inval_skb:
+	kfree_skb(skb);
+	dev->stats.tx_dropped++;
+	return 1;
 }
 
 struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
include/linux/can/raw.h +2 -1
index 781f3a3..5448c0f 100644
@@ -23,7 +23,8 @@ enum {
 	CAN_RAW_FILTER = 1,	/* set 0 .. n can_filter(s)          */
 	CAN_RAW_ERR_FILTER,	/* set filter for error frames       */
 	CAN_RAW_LOOPBACK,	/* local loopback (default:on)       */
-	CAN_RAW_RECV_OWN_MSGS	/* receive my own msgs (default:off) */
+	CAN_RAW_RECV_OWN_MSGS,	/* receive my own msgs (default:off) */
+	CAN_RAW_FD_FRAMES,	/* use struct canfd_frame (default:off) */
 };
 
 #endif
include/linux/if_ether.h +1 -0
index 56d907a..5c9c2b4 100644
@@ -119,6 +119,7 @@
 #define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
 #define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
 #define ETH_P_CAIF	0x00F7		/* ST-Ericsson CAIF protocol	*/
+#define ETH_P_CANFD	0x00FD		/* Controller Area Network FD   */
 
 /*
  *	This is an Ethernet frame header.
net/can/af_can.c +74 -19

158 lines not on this page · raw message

net/can/bcm.c +2 -0
index 151b773..2060945 100644
@@ -265,6 +265,7 @@ static void bcm_can_tx(struct bcm_op *op)
 	/* send with loopback */
 	skb->dev = dev;
 	skb->sk = op->sk;
+	skb->protocol = htons(ETH_P_CAN);
 	can_send(skb, 1);
 
 	/* update statistics */
@@ -1215,6 +1216,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
 
 	skb->dev = dev;
 	skb->sk  = sk;
+	skb->protocol = htons(ETH_P_CAN);
 	err = can_send(skb, 1); /* send with loopback */
 	dev_put(dev);
 
net/can/raw.c +44 -2

93 lines not on this page · raw message

#1 lore raw
Quoted 21 lines · Oliver Hartkopp
drivers/net/can/dev.c +1 -1
index f03d7a4..1b7e843 100644
@@ -454,7 +454,7 @@ EXPORT_SYMBOL_GPL(can_bus_off);
 static void can_setup(struct net_device *dev)
 {
 	dev->type = ARPHRD_CAN;
-	dev->mtu = sizeof(struct can_frame);
+	dev->mtu = CAN_MTU;
 	dev->hard_header_len = 0;
 	dev->addr_len = 0;
 	dev->tx_queue_len = 10;
drivers/net/can/vcan.c +0 -0
index ea2d942..bddbafb 100644

drivers/net/can/vcan.c static void vcan_rx(struct sk_buff *skb, struct net_device *dev) · line 77

Quoted 5 lines
drivers/net/can/vcan.c +1 -1
@@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 
 	stats->rx_packets++;
-	stats->rx_bytes += cf->can_dlc;
+	stats->rx_bytes += can_dlc2len(cf->can_dlc);

Hm, I think "cf->can_dlc" should contain the *real* length. That would simplify things a lot. The conversion is done when the corresponding DLC registers are read or written.

Wolfgang.

author maintainer
#2 lore raw
Quoted 7 lines · Wolfgang Grandegger
Quoted 7 lines
drivers/net/can/vcan.c +0 -0
index ea2d942..bddbafb 100644
@@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 
Quoted 7 lines

drivers/net/can/vcan.c static void vcan_rx(struct sk_buff *skb, struct net_device *dev) · line 77

Quoted 3 lines
drivers/net/can/vcan.c +1 -1
 	stats->rx_packets++;
-	stats->rx_bytes += cf->can_dlc;
+	stats->rx_bytes += can_dlc2len(cf->can_dlc);

Hm, I think "cf->can_dlc" should contain the *real* length. That would simplify things a lot. The conversion is done when the corresponding DLC registers are read or written.

I thought about this idea some time too.

My problem was that 'can_dlc' says

"CAN data length *code*"

And the dlc for CAN is already well defined.

From a todays view cf->len would indeed be a better expression :-/

We could generally think about a union of 'can_dlc' and 'len' though, where can_dlc would not be part of struct canfd_frame but only the len value.

As you can see here, i also had the idea of providing both values:

https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869

But is was a bad design, as you have two APIs modifying one value - you never know what to trust ... it was a sanity check hell.

Regards,
Oliver

#3 lore raw
Quoted 18 lines · Oliver Hartkopp
Quoted 7 lines · Wolfgang Grandegger
Quoted 7 lines
drivers/net/can/vcan.c +0 -0
index ea2d942..bddbafb 100644
@@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 
Quoted 7 lines

drivers/net/can/vcan.c static void vcan_rx(struct sk_buff *skb, struct net_device *dev) · line 77

Quoted 3 lines
drivers/net/can/vcan.c +1 -1
 	stats->rx_packets++;
-	stats->rx_bytes += cf->can_dlc;
+	stats->rx_bytes += can_dlc2len(cf->can_dlc);

Hm, I think "cf->can_dlc" should contain the *real* length. That would simplify things a lot. The conversion is done when the corresponding DLC registers are read or written.

Quoted 9 lines

I thought about this idea some time too.

My problem was that 'can_dlc' says

"CAN data length *code*"

And the dlc for CAN is already well defined.

Quoted 1 line

From a todays view cf->len would indeed be a better expression :-/

Yes, definitely.

Quoted 3 lines

We could generally think about a union of 'can_dlc' and 'len' though, where can_dlc would not be part of struct canfd_frame but only the len value.

Well, we do not need dlc in the struct, just len. The conversion len->dlc needs just to be done once when register is read/written.

Quoted 6 lines

As you can see here, i also had the idea of providing both values:

https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869

But is was a bad design, as you have two APIs modifying one value - you never know what to trust ... it was a sanity check hell.

If "cf->can_dlc", or however it is named, does not contain the real length, we will end up in a dlc2len conversion nightmare. Be aware the the struct is also used by the app.

Wolfgang.

#4 lore raw

Re: [RFC] CAN FD support

Quoted 40 lines · Wolfgang Grandegger
Quoted 18 lines · Oliver Hartkopp
Quoted 7 lines · Wolfgang Grandegger
Quoted 7 lines
drivers/net/can/vcan.c +0 -0
index ea2d942..bddbafb 100644
@@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 
Quoted 7 lines

drivers/net/can/vcan.c static void vcan_rx(struct sk_buff *skb, struct net_device *dev) · line 77

Quoted 3 lines
drivers/net/can/vcan.c +1 -1
 	stats->rx_packets++;
-	stats->rx_bytes += cf->can_dlc;
+	stats->rx_bytes += can_dlc2len(cf->can_dlc);

Hm, I think "cf->can_dlc" should contain the *real* length. That would simplify things a lot. The conversion is done when the corresponding DLC registers are read or written.

Quoted 9 lines

I thought about this idea some time too.

My problem was that 'can_dlc' says

"CAN data length *code*"

And the dlc for CAN is already well defined.

Quoted 1 line

From a todays view cf->len would indeed be a better expression :-/

Yes, definitely.

Quoted 3 lines

We could generally think about a union of 'can_dlc' and 'len' though, where can_dlc would not be part of struct canfd_frame but only the len value.

Well, we do not need dlc in the struct, just len. The conversion len->dlc needs just to be done once when register is read/written.

Quoted 2 lines

As you can see here, i also had the idea of providing both values:

Quoted 7 lines
Quoted 4 lines

https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869

But is was a bad design, as you have two APIs modifying one value - you never know what to trust ... it was a sanity check hell.

If "cf->can_dlc", or however it is named, does not contain the real length, we will end up in a dlc2len conversion nightmare. Be aware the

I share this.
I'd even prefer u16 over u8 even.
No legacy issues exist when changing the meaning of can_dlc, since current CAN frames have equal values for DLC & length!

Quoted 7 lines

the struct is also used by the app.

Wolfgang.
--
To unsubscribe from this list: send the line "unsubscribe linux-can" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#5 lore raw

Re: [RFC] CAN FD support

Quoted 46 lines · Kurt Van Dijck
Quoted 45 lines · Wolfgang Grandegger
Quoted 18 lines · Oliver Hartkopp
Quoted 7 lines · Wolfgang Grandegger
Quoted 7 lines
drivers/net/can/vcan.c +0 -0
index ea2d942..bddbafb 100644
@@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 
Quoted 7 lines

drivers/net/can/vcan.c static void vcan_rx(struct sk_buff *skb, struct net_device *dev) · line 77

Quoted 3 lines
drivers/net/can/vcan.c +1 -1
 	stats->rx_packets++;
-	stats->rx_bytes += cf->can_dlc;
+	stats->rx_bytes += can_dlc2len(cf->can_dlc);

Hm, I think "cf->can_dlc" should contain the *real* length. That would simplify things a lot. The conversion is done when the corresponding DLC registers are read or written.

Quoted 9 lines

I thought about this idea some time too.

My problem was that 'can_dlc' says

"CAN data length *code*"

And the dlc for CAN is already well defined.

Quoted 1 line

From a todays view cf->len would indeed be a better expression :-/

Yes, definitely.

Quoted 3 lines

We could generally think about a union of 'can_dlc' and 'len' though, where can_dlc would not be part of struct canfd_frame but only the len value.

Well, we do not need dlc in the struct, just len. The conversion len->dlc needs just to be done once when register is read/written.

Quoted 6 lines

As you can see here, i also had the idea of providing both values:

https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869

But is was a bad design, as you have two APIs modifying one value - you never know what to trust ... it was a sanity check hell.

Quoted 9 lines
Quoted 2 lines

If "cf->can_dlc", or however it is named, does not contain the real length, we will end up in a dlc2len conversion nightmare. Be aware the

I share this.
I'd even prefer u16 over u8 even.
No legacy issues exist when changing the meaning of can_dlc, since current CAN frames have equal values for DLC & length!

Quoted 1 line

the struct is also used by the app.

Yes - that's the main problem IMO.

What about this binary compatible introduction of cf->len ...

drivers/net/can/vcan.c +1 -1
index bddbafb..366924e 100644
@@ -74,7 +74,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 
 	stats->rx_packets++;
-	stats->rx_bytes += can_dlc2len(cf->can_dlc);
+	stats->rx_bytes += cf->len;
 
 	skb->pkt_type  = PACKET_BROADCAST;
 	skb->dev       = dev;
@@ -93,7 +93,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct

net_device *dev)
return NETDEV_TX_OK;

stats->tx_packets++;
- stats->tx_bytes += can_dlc2len(cf->can_dlc);
+ stats->tx_bytes += cf->len;

/* set flag whether this packet has to be looped back */ loop = skb->pkt_type == PACKET_LOOPBACK;
@@ -107,7 +107,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
* CAN core already did the echo for us */
stats->rx_packets++;
- stats->rx_bytes += can_dlc2len(cf->can_dlc);
+ stats->rx_bytes += cf->len;
}
kfree_skb(skb);
return NETDEV_TX_OK;

include/linux/can.h +5 -2
index 74052da..b99f9f1 100644
@@ -57,7 +57,10 @@ typedef __u32 can_err_mask_t;
  */
 struct can_frame {
 	canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
-	__u8    can_dlc; /* data length code: 0 .. 8 */
+	union {
+		__u8    can_dlc; /* data length code: 0 .. 8 */
+		__u8    len; /* data length: 0 .. 8 */
+	};
 	__u8    data[8] __attribute__((aligned(8)));
 };
 
@@ -84,7 +87,7 @@ struct can_frame {
  */
 struct canfd_frame {
 	canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
-	__u8    can_dlc; /* CAN FD data length code: 0 .. 0xF */
+	__u8    len;     /* data length: 0 .. 64 */
 	__u8    flags;   /* additional flags for CAN FD */
 	__u8    __res0;  /* reserved / padding */
 	__u8    __res1;  /* reserved / padding */
net/can/af_can.c +1 -1
index 1b7f1f8..9986d9c 100644
@@ -875,7 +875,7 @@ static __init int can_init(void)
 {
 	/* check for correct padding that can_dlc owns always the same position */
 	BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
-		     offsetof(struct canfd_frame, can_dlc));
+		     offsetof(struct canfd_frame, len));
 
 	printk(banner);
 
#6 lore raw

Re: [RFC] CAN FD support

Quoted 56 lines · Oliver Hartkopp
Quoted 54 lines · Kurt Van Dijck
Quoted 40 lines · Wolfgang Grandegger
Quoted 18 lines · Oliver Hartkopp
Quoted 7 lines · Wolfgang Grandegger
Quoted 7 lines
drivers/net/can/vcan.c +0 -0
index ea2d942..bddbafb 100644
@@ -74,9 +74,8 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 
Quoted 7 lines

drivers/net/can/vcan.c static void vcan_rx(struct sk_buff *skb, struct net_device *dev) · line 77

Quoted 3 lines
drivers/net/can/vcan.c +1 -1
 	stats->rx_packets++;
-	stats->rx_bytes += cf->can_dlc;
+	stats->rx_bytes += can_dlc2len(cf->can_dlc);

Hm, I think "cf->can_dlc" should contain the *real* length. That would simplify things a lot. The conversion is done when the corresponding DLC registers are read or written.

Quoted 9 lines

I thought about this idea some time too.

My problem was that 'can_dlc' says

"CAN data length *code*"

And the dlc for CAN is already well defined.

Quoted 1 line

From a todays view cf->len would indeed be a better expression :-/

Yes, definitely.

Quoted 3 lines

We could generally think about a union of 'can_dlc' and 'len' though, where can_dlc would not be part of struct canfd_frame but only the len value.

Well, we do not need dlc in the struct, just len. The conversion len->dlc needs just to be done once when register is read/written.

Quoted 2 lines

As you can see here, i also had the idea of providing both values:

Quoted 7 lines
Quoted 4 lines

https://gitorious.org/~hartkopp/linux-can/hartkopps-linux-can-next/commit/dc730b789cc1a6a3c04aaacde02c6a5a81988869

But is was a bad design, as you have two APIs modifying one value - you never know what to trust ... it was a sanity check hell.

If "cf->can_dlc", or however it is named, does not contain the real length, we will end up in a dlc2len conversion nightmare. Be aware the

I share this.
I'd even prefer u16 over u8 even.
No legacy issues exist when changing the meaning of can_dlc, since current CAN frames have equal values for DLC & length!

Quoted 4 lines
Quoted 1 line
Quoted 1 line

the struct is also used by the app.

Yes - that's the main problem IMO.

Furthermore, the user should be allowed to specify *any* lenght below max, als 57 bytes. It's than up to the driver to do the necessary padding.

Quoted 2 lines

What about this binary compatible introduction of cf->len ...

Looks good.

Wolfgang.

#7 lore raw

Re: [RFC] CAN FD support

Quoted 3 lines

Furthermore, the user should be allowed to specify *any* lenght below max, als 57 bytes. It's than up to the driver to do the necessary padding.

I think Oliver solved this (on af_can level?) with a table len2dlc (static in the header?)

Quoted 5 lines
Quoted 3 lines

What about this binary compatible introduction of cf->len ...

Looks good.

Yep, given 2 structs, this illustrates the contents very well!

Kurt

author maintainer
#8 lore raw

Re: [RFC] CAN FD support

Quoted 4 lines · Kurt Van Dijck
Quoted 3 lines

Furthermore, the user should be allowed to specify *any* lenght below max, als 57 bytes. It's than up to the driver to do the necessary padding.

I think Oliver solved this (on af_can level?) with a table len2dlc (static in the header?)

Yes - it was the only way not to make it clash when linking proc.o and af_can.o together.

Btw. if we move this functionality to the driver, i would like to move it from can.h into dev.c :-)

Quoted 7 lines
Quoted 6 lines
Quoted 4 lines

What about this binary compatible introduction of cf->len ...

Looks good.

Yep, given 2 structs, this illustrates the contents very well!

Fine.

One question:

What about omitting the union in struct can_frame modification and leave it as it is since the first days of SocketCAN?

We can still check these offsets

BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
- offsetof(struct canfd_frame, can_dlc));
+ offsetof(struct canfd_frame, len));

and can (kernel) internally use struct canfd_frame as reference:

	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
	struct net_device_stats *stats = &dev->stats;

	stats->rx_packets++;
	stats->rx_bytes += cfd->len;

which would cover cf->can_dlc in the same way.

I wonder, if people would start to use can_frame.len once it is defined as this would not be backward compatible code (but binary compatible).

Regards,
Oliver

#9 lore raw

Re: [RFC] CAN FD support

In reply to Oliver Hartkopp

On 05/03/2012 02:38 PM, Oliver Hartkopp wrote:
[...]

Quoted 11 lines
Quoted 6 lines

I share this.
I'd even prefer u16 over u8 even.
No legacy issues exist when changing the meaning of can_dlc, since current CAN frames have equal values for DLC & length!

Quoted 1 line

the struct is also used by the app.

Yes - that's the main problem IMO.

What about this binary compatible introduction of cf->len ...

...but it's not 100% source compatible, due to a compiler bug in gcc. You cannot use C99 initializers on anonymous unions in certain gcc versions.

[..]

include/linux/can.h typedef __u32 can_err_mask_t; · line 65

Quoted 13 lines
include/linux/can.h +4 -1
@@ -57,7 +57,10 @@ typedef __u32 can_err_mask_t;
  */
 struct can_frame {
 	canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
-	__u8    can_dlc; /* data length code: 0 .. 8 */
+	union {
+		__u8    can_dlc; /* data length code: 0 .. 8 */
+		__u8    len; /* data length: 0 .. 8 */
+	};
 	__u8    data[8] __attribute__((aligned(8)));
 };

Marc

Signature · 4 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |
author maintainer
#10 lore raw

Re: [RFC] CAN FD support

Quoted 11 lines · Marc Kleine-Budde

On 05/03/2012 02:38 PM, Oliver Hartkopp wrote:
[...]

Quoted 8 lines
Quoted 6 lines

I share this.
I'd even prefer u16 over u8 even.
No legacy issues exist when changing the meaning of can_dlc, since current CAN frames have equal values for DLC & length!

Quoted 1 line

the struct is also used by the app.

Quoted 6 lines
Quoted 3 lines

Yes - that's the main problem IMO.

What about this binary compatible introduction of cf->len ...

...but it's not 100% source compatible, due to a compiler bug in gcc. You cannot use C99 initializers on anonymous unions in certain gcc versions.

ugh!

Quoted 17 lines

[..]

include/linux/can.h typedef __u32 can_err_mask_t; · line 65

Quoted 13 lines
include/linux/can.h +4 -1
@@ -57,7 +57,10 @@ typedef __u32 can_err_mask_t;
  */
 struct can_frame {
 	canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
-	__u8    can_dlc; /* data length code: 0 .. 8 */
+	union {
+		__u8    can_dlc; /* data length code: 0 .. 8 */
+		__u8    len; /* data length: 0 .. 8 */
+	};
 	__u8    data[8] __attribute__((aligned(8)));
 };

Thanks for the hint.

Indeed i left the struct can_frame as is now!

There's now can_frame.can_dlc and canfd_frame.len which both contains the real length - even if can_frame.can_dlc is literally a data length *code* .

Btw. by having canfd_frame.len we indicate for CAN FD that we have a real length here.

Regards,
Oliver