can: set CANFD_FDF flag in all CAN FD frame structures
authorOliver Hartkopp <socketcan@hartkopp.net>
Mon, 12 Sep 2022 17:07:21 +0000 (19:07 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Thu, 15 Sep 2022 07:08:08 +0000 (09:08 +0200)
To simplify the testing in user space all struct canfd_frame's provided by
the CAN subsystem of the Linux kernel now have the CANFD_FDF flag set in
canfd_frame::flags.

NB: Handcrafted ETH_P_CANFD frames introduced via PF_PACKET socket might
not set this bit correctly. During the check for sufficient headroom in
PF_PACKET sk_buffs the uninitialized CAN sk_buff data structures are filled.
In the case of a CAN FD frame the CANFD_FDF flag is set accordingly.

As the CAN frame content is already zero initialized in alloc_canfd_skb()
the obsolete initialization of cf->flags in the CTU CAN FD driver has been
removed as it would overwrite the already set CANFD_FDF flag.

Acked-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/all/20220912170725.120748-4-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/ctucanfd/ctucanfd_base.c
drivers/net/can/dev/skb.c
include/uapi/linux/can.h
net/can/af_can.c

index 3c18d02..c402671 100644 (file)
@@ -657,7 +657,6 @@ static void ctucan_read_rx_frame(struct ctucan_priv *priv, struct canfd_frame *c
                cf->can_id = (idw >> 18) & CAN_SFF_MASK;
 
        /* BRS, ESI, RTR Flags */
-       cf->flags = 0;
        if (FIELD_GET(REG_FRAME_FORMAT_W_FDF, ffw)) {
                if (FIELD_GET(REG_FRAME_FORMAT_W_BRS, ffw))
                        cf->flags |= CANFD_BRS;
index b896e1c..adb413b 100644 (file)
@@ -244,6 +244,9 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
 
        *cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
 
+       /* set CAN FD flag by default */
+       (*cfd)->flags = CANFD_FDF;
+
        return skb;
 }
 EXPORT_SYMBOL_GPL(alloc_canfd_skb);
@@ -287,6 +290,14 @@ static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb)
                skb_reset_mac_header(skb);
                skb_reset_network_header(skb);
                skb_reset_transport_header(skb);
+
+               /* set CANFD_FDF flag for CAN FD frames */
+               if (can_is_canfd_skb(skb)) {
+                       struct canfd_frame *cfd;
+
+                       cfd = (struct canfd_frame *)skb->data;
+                       cfd->flags |= CANFD_FDF;
+               }
        }
 
        return true;
index 90801ad..7b23eee 100644 (file)
@@ -141,8 +141,8 @@ struct can_frame {
  * When this is done the former differentiation via CAN_MTU / CANFD_MTU gets
  * lost. CANFD_FDF allows programmers to mark CAN FD frames in the case of
  * using struct canfd_frame for mixed CAN / CAN FD content (dual use).
- * N.B. the Kernel APIs do NOT provide mixed CAN / CAN FD content inside of
- * struct canfd_frame therefore the CANFD_FDF flag is disregarded by Linux.
+ * Since the introduction of CAN XL the CANFD_FDF flag is set in all CAN FD
+ * frame structures provided by the CAN subsystem of the Linux kernel.
  */
 #define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
 #define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
index afa6c21..072a6a5 100644 (file)
@@ -205,7 +205,12 @@ int can_send(struct sk_buff *skb, int loop)
        if (can_is_can_skb(skb)) {
                skb->protocol = htons(ETH_P_CAN);
        } else if (can_is_canfd_skb(skb)) {
+               struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
                skb->protocol = htons(ETH_P_CANFD);
+
+               /* set CAN FD flag for CAN FD frames by default */
+               cfd->flags |= CANFD_FDF;
        } else {
                goto inval_skb;
        }