Commit 94c23097 authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by Marc Kleine-Budde

can: gw: support modification of Classical CAN DLCs

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: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/r/20201119084921.2621-1-socketcan@hartkopp.netSigned-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 396b3ced
...@@ -98,8 +98,8 @@ enum { ...@@ -98,8 +98,8 @@ enum {
/* CAN frame elements that are affected by curr. 3 CAN frame modifications */ /* CAN frame elements that are affected by curr. 3 CAN frame modifications */
#define CGW_MOD_ID 0x01 #define CGW_MOD_ID 0x01
#define CGW_MOD_DLC 0x02 /* contains the data length in bytes */ #define CGW_MOD_DLC 0x02 /* Classical CAN data length code */
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD length representation */ #define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD (plain) data length */
#define CGW_MOD_DATA 0x04 #define CGW_MOD_DATA 0x04
#define CGW_MOD_FLAGS 0x08 /* CAN FD flags */ #define CGW_MOD_FLAGS 0x08 /* CAN FD flags */
......
...@@ -199,6 +199,68 @@ static void mod_set_fddata(struct canfd_frame *cf, struct cf_mod *mod) ...@@ -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); 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) static void canframecpy(struct canfd_frame *dst, struct can_frame *src)
{ {
/* Copy the struct members separately to ensure that no uninitialized /* Copy the struct members separately to ensure that no uninitialized
...@@ -842,8 +904,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, ...@@ -842,8 +904,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if (mb.modtype & CGW_MOD_ID) if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_and_id; mod->modfunc[modidx++] = mod_and_id;
if (mb.modtype & CGW_MOD_LEN) if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_and_len; mod->modfunc[modidx++] = mod_and_ccdlc;
if (mb.modtype & CGW_MOD_DATA) if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_and_data; mod->modfunc[modidx++] = mod_and_data;
...@@ -858,8 +920,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, ...@@ -858,8 +920,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if (mb.modtype & CGW_MOD_ID) if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_or_id; mod->modfunc[modidx++] = mod_or_id;
if (mb.modtype & CGW_MOD_LEN) if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_or_len; mod->modfunc[modidx++] = mod_or_ccdlc;
if (mb.modtype & CGW_MOD_DATA) if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_or_data; mod->modfunc[modidx++] = mod_or_data;
...@@ -874,8 +936,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, ...@@ -874,8 +936,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if (mb.modtype & CGW_MOD_ID) if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_xor_id; mod->modfunc[modidx++] = mod_xor_id;
if (mb.modtype & CGW_MOD_LEN) if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_xor_len; mod->modfunc[modidx++] = mod_xor_ccdlc;
if (mb.modtype & CGW_MOD_DATA) if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_xor_data; mod->modfunc[modidx++] = mod_xor_data;
...@@ -890,8 +952,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, ...@@ -890,8 +952,8 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if (mb.modtype & CGW_MOD_ID) if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_set_id; mod->modfunc[modidx++] = mod_set_id;
if (mb.modtype & CGW_MOD_LEN) if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_set_len; mod->modfunc[modidx++] = mod_set_ccdlc;
if (mb.modtype & CGW_MOD_DATA) if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_set_data; mod->modfunc[modidx++] = mod_set_data;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment