Skip to content

Commit

Permalink
can: gw: support modification of Classical CAN DLCs
Browse files Browse the repository at this point in the history
Add support for data length code modifications for Classical CAN.

The netlink configuration interface always allowed to pass any value
that fits into a byte, therefore only the modification process had to be
extended to handle the raw DLC represenation of Classical CAN frames.

When a DLC value from 0 .. F is provided for Classical CAN frame
modifications the 'len' value is modified as-is with the exception that
potentially existing 9 .. F DLC values in the len8_dlc element are moved
to the 'len' element for the modification operation by mod_retrieve_ccdlc().

After the modification the Classical CAN frame DLC information is brought
back into the correct format by mod_store_ccdlc() which is filling 'len'
and 'len8_dlc' accordingly.

Signed-off-by: Oliver Hartkopp <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Marc Kleine-Budde <[email protected]>
  • Loading branch information
hartkopp authored and marckleinebudde committed Nov 20, 2020
1 parent 396b3ce commit 94c2309
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 10 deletions.
4 changes: 2 additions & 2 deletions include/uapi/linux/can/gw.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ enum {

/* CAN frame elements that are affected by curr. 3 CAN frame modifications */
#define CGW_MOD_ID 0x01
#define CGW_MOD_DLC 0x02 /* contains the data length in bytes */
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD length representation */
#define CGW_MOD_DLC 0x02 /* Classical CAN data length code */
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD (plain) data length */
#define CGW_MOD_DATA 0x04
#define CGW_MOD_FLAGS 0x08 /* CAN FD flags */

Expand Down
78 changes: 70 additions & 8 deletions net/can/gw.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,68 @@ static void mod_set_fddata(struct canfd_frame *cf, struct cf_mod *mod)
memcpy(cf->data, mod->modframe.set.data, CANFD_MAX_DLEN);
}

/* retrieve valid CC DLC value and store it into 'len' */
static void mod_retrieve_ccdlc(struct canfd_frame *cf)
{
struct can_frame *ccf = (struct can_frame *)cf;

/* len8_dlc is only valid if len == CAN_MAX_DLEN */
if (ccf->len != CAN_MAX_DLEN)
return;

/* do we have a valid len8_dlc value from 9 .. 15 ? */
if (ccf->len8_dlc > CAN_MAX_DLEN && ccf->len8_dlc <= CAN_MAX_RAW_DLC)
ccf->len = ccf->len8_dlc;
}

/* convert valid CC DLC value in 'len' into struct can_frame elements */
static void mod_store_ccdlc(struct canfd_frame *cf)
{
struct can_frame *ccf = (struct can_frame *)cf;

/* clear potential leftovers */
ccf->len8_dlc = 0;

/* plain data length 0 .. 8 - that was easy */
if (ccf->len <= CAN_MAX_DLEN)
return;

/* potentially broken values are catched in can_can_gw_rcv() */
if (ccf->len > CAN_MAX_RAW_DLC)
return;

/* we have a valid dlc value from 9 .. 15 in ccf->len */
ccf->len8_dlc = ccf->len;
ccf->len = CAN_MAX_DLEN;
}

static void mod_and_ccdlc(struct canfd_frame *cf, struct cf_mod *mod)
{
mod_retrieve_ccdlc(cf);
mod_and_len(cf, mod);
mod_store_ccdlc(cf);
}

static void mod_or_ccdlc(struct canfd_frame *cf, struct cf_mod *mod)
{
mod_retrieve_ccdlc(cf);
mod_or_len(cf, mod);
mod_store_ccdlc(cf);
}

static void mod_xor_ccdlc(struct canfd_frame *cf, struct cf_mod *mod)
{
mod_retrieve_ccdlc(cf);
mod_xor_len(cf, mod);
mod_store_ccdlc(cf);
}

static void mod_set_ccdlc(struct canfd_frame *cf, struct cf_mod *mod)
{
mod_set_len(cf, mod);
mod_store_ccdlc(cf);
}

static void canframecpy(struct canfd_frame *dst, struct can_frame *src)
{
/* Copy the struct members separately to ensure that no uninitialized
Expand Down Expand Up @@ -842,8 +904,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_and_id;

if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_and_len;
if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_and_ccdlc;

if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_and_data;
Expand All @@ -858,8 +920,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_or_id;

if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_or_len;
if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_or_ccdlc;

if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_or_data;
Expand All @@ -874,8 +936,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_xor_id;

if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_xor_len;
if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_xor_ccdlc;

if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_xor_data;
Expand All @@ -890,8 +952,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_set_id;

if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_set_len;
if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_set_ccdlc;

if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_set_data;
Expand Down

0 comments on commit 94c2309

Please sign in to comment.