Re: [RFC PATCH 1/5] can: canxl: introduce CAN XL data structure

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu. 14 Jul. 2022 at 05:02, Oliver Hartkopp <socketcan@xxxxxxxxxxxx> wrote:
> On 13.07.22 03:07, Vincent Mailhol wrote:
> > On Wed. 13 Jul. 2022 at 04:24, Oliver Hartkopp <socketcan@xxxxxxxxxxxx> wrote:
> > Well, if we document than can_frame::__pad shall be zero for mix
> > usages (i.e. comments in struct can_frame and updated kernel doc),
> > then we would have done our due diligence. From that point, if people
> > ignore the documentation *and* do not follow best practices for safety
> > application development, I wouldn't cry.
>
> Right. As long as we did not enable CAN_XL we do not need to take care.
> And introducing the restriction to set __pad to zero together with the
> new CAN_XL option seems legit.

ACK. I draw the line between the already existing applications and the
yet to be written ones. If we are safe for the existing ones, then I
think we are good to go.

> > If we absolutely want to prevent struct can_frame to be interpreted as
> > a canxl_frame due to some stack garbage, we can add one
> > padding/reserved field like that:
> >
> > struct canxl_frame {
> >          canid_t prio;  /* 11 bit priority for arbitration (canid_t) */
> >          __u8    sdt;   /* SDU (service data unit) type */
> >          __u8    flags; /* additional flags for CAN XL */
> >          __u16   len;   /* frame payload length in byte */
> >          __u32   af;    /* acceptance field */
> >          __u32 __res; /* reserved field. Shall be zero */
> >          __u8    data[] __attribute__((aligned(8)));
> > };
> >
> > This way, the minimum transfer unit of CANXL is 17 bytes (16 for
> > header and 1 for data) which is exactly one byte more than can_frame
> > (and we get back the 8 bytes alignment \o/)
> >
> > This would only leave the risk of having some garbage in
> > canfd_frame::flags, e.g. if user does:
> >
> >          struct canfd_frame cfd; /* declared on the stack and not initialized */
> >          cfd.flags |= <some_flags> /* use |= instead of = */
> >
> > But this is already risky for plain CAN-FD.
>
> Hm, this brings me to an even more weird idea:
>
> struct canxl_frame {
>          canid_t prio;  /* 11 bit priority for arbitration (canid_t) */
>          __u8    sec:1, /* SEC bit */
>                  xltag:7; /* all bits set */
>          __u8    sdt;   /* SDU (service data unit) type */
>          __u16   len;   /* frame payload length in byte */
>          __u32   af;    /* acceptance field */
>          __u8    data[CANXL_MAX_DLEN];
> };
>
> We could set the first byte (former len element) to a value of 0x7F and
> define the SEC bit as 0x80.

Beware! You just stepped in the realm of undefined behaviours! The
order of the bitfields is implementation specific...

Ref: ISO/IEC 9899:1999 section 6.7.2.1 "Structure and union
specifiers" paragraph 10:

| The order of allocation of bit-fields within a unit (high-order to
| low-order or low-order to high-order) is implementation-defined.

Example, on my x86_64 machine, this code:

/*********** begin **********/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

union foo {
        struct {
                uint8_t sec:1, /* SEC bit */
                        xltag:7; /* all bits set */
        };
        uint8_t raw;
};

int main()
{
        union foo foo;

        foo.sec = 1;
        printf("foo.raw: 0x%x\n", foo.raw);

        return EXIT_SUCCESS;
}
/*********** end ************/

will return: "foo.raw: 0x1" instead of the expected 0x80.

The correct declaration is:

/*********** begin **********/
#include <asm/byteorder.h>

struct canxl_frame {
        canid_t prio;  /* 11 bit priority for arbitration (canid_t) */
#if defined(__LITTLE_ENDIAN_BITFIELD)
        __u8    xltag:7, /* all bits set */
                sec:1; /* SEC bit */
#else /* __BIG_ENDIAN_BITFIELD */
        __u8    sec:1, /* SEC bit */
                xltag:7; /* all bits set */
#endif
        __u8    sdt;   /* SDU (service data unit) type */
        __u16   len;   /* frame payload length in byte */
        __u32   af;    /* acceptance field */
        __u8    data[CANXL_MAX_DLEN];
};
/*********** end ************/

And this starts to be a really convoluted solution.

> This would mean that we use the former length element to indicate the
> CAN XL frame as no CAN/CANFD frame can have a length of 127 and above.
>
> Not sure if it makes sense to define some bits as depicted above, or if
> we should define a __u8 xlsec ?

If we follow your idea, use __u8 xlsec in order to avoid undefined behaviours.

> Where we define
>
> #define CANXL_TAG 0x7F

Here, you "burn" all the flags for future usage.
FYI, this doesn't have to be 0x7F. It could be any of the length
values not allowed by CAN-FD, namely (in decimal): 9-11, 13-15, 17-19,
21-23, 25-31, 33-47, 49-63

> #define CANXL_SEC 0x80

I did not get why CANXL_XLF isn't needed anymore.

> which has to be set in the xlsec element then.
>
> With this move we get rid of any flags problems (we only need the SEC
> bit anyway) and define a clear 'escape value' in the former length element.

If I try to bounce on your idea, I will propose:

/*********** begin **********/
struct canxl_frame {
        canid_t prio;  /* 11 bit priority for arbitration (canid_t) */
        __u8    flags; /* additional flags for CAN XL. MSB must be set */
        __u8    sdt;   /* SDU (service data unit) type */
        __u16   len;   /* frame payload length in bytes */
        __u32   af;    /* acceptance field */
        __u8    data[];
};

#define CANXL_XLF 0x01 /* mark CAN XL for dual use of struct canfd_frame */
#define CANXL_SEC 0x02 /* Simple Extended Content (security/segmentation) */
#define CANXL_DISCRIMINATOR 0x80; /* Mandatory to distinguish between
CAN(-FD) and XL frames */
/*********** end ************/

This has no undefined behaviour and we still have five flags (0x04 to
0x40) for future use.


Yours sincerely,
Vincent Mailhol



[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux