Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: gw: add support for CAN FD frames

Introduce CAN FD support which needs an extension of the netlink API to
pass CAN FD type content to the kernel which has a different size to
Classic CAN. Additionally the struct canfd_frame has a new 'flags' element
that can now be modified with can-gw.

The new CGW_FLAGS_CAN_FD option flag defines whether the routing job
handles Classic CAN or CAN FD frames. This setting is very strict at
reception time and enables the new possibilities, e.g. CGW_FDMOD_* and
modifying the flags element of struct canfd_frame, only when
CGW_FLAGS_CAN_FD is set.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
456a8a64 e9dc7c60

+200 -28
+13 -1
include/uapi/linux/can/gw.h
··· 80 80 CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */ 81 81 CGW_LIM_HOPS, /* limit the number of hops of this specific rule */ 82 82 CGW_MOD_UID, /* user defined identifier for modification updates */ 83 + CGW_FDMOD_AND, /* CAN FD frame modification binary AND */ 84 + CGW_FDMOD_OR, /* CAN FD frame modification binary OR */ 85 + CGW_FDMOD_XOR, /* CAN FD frame modification binary XOR */ 86 + CGW_FDMOD_SET, /* CAN FD frame modification set alternate values */ 83 87 __CGW_MAX 84 88 }; 85 89 ··· 92 88 #define CGW_FLAGS_CAN_ECHO 0x01 93 89 #define CGW_FLAGS_CAN_SRC_TSTAMP 0x02 94 90 #define CGW_FLAGS_CAN_IIF_TX_OK 0x04 91 + #define CGW_FLAGS_CAN_FD 0x08 95 92 96 93 #define CGW_MOD_FUNCS 4 /* AND OR XOR SET */ 97 94 ··· 101 96 #define CGW_MOD_DLC 0x02 /* contains the data length in bytes */ 102 97 #define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD length representation */ 103 98 #define CGW_MOD_DATA 0x04 99 + #define CGW_MOD_FLAGS 0x08 /* CAN FD flags */ 104 100 105 - #define CGW_FRAME_MODS 3 /* ID DLC/LEN DATA */ 101 + #define CGW_FRAME_MODS 4 /* ID DLC/LEN DATA FLAGS */ 106 102 107 103 #define MAX_MODFUNCTIONS (CGW_MOD_FUNCS * CGW_FRAME_MODS) 108 104 ··· 112 106 __u8 modtype; 113 107 } __attribute__((packed)); 114 108 109 + struct cgw_fdframe_mod { 110 + struct canfd_frame cf; 111 + __u8 modtype; 112 + } __attribute__((packed)); 113 + 115 114 #define CGW_MODATTR_LEN sizeof(struct cgw_frame_mod) 115 + #define CGW_FDMODATTR_LEN sizeof(struct cgw_fdframe_mod) 116 116 117 117 struct cgw_csum_xor { 118 118 __s8 from_idx;
+187 -27
net/can/gw.c
··· 1 1 // SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 2 /* gw.c - CAN frame Gateway/Router/Bridge with netlink interface 3 3 * 4 - * Copyright (c) 2017 Volkswagen Group Electronic Research 4 + * Copyright (c) 2019 Volkswagen Group Electronic Research 5 5 * All rights reserved. 6 6 * 7 7 * Redistribution and use in source and binary forms, with or without ··· 59 59 #include <net/net_namespace.h> 60 60 #include <net/sock.h> 61 61 62 - #define CAN_GW_VERSION "20170425" 62 + #define CAN_GW_VERSION "20190810" 63 63 #define CAN_GW_NAME "can-gw" 64 64 65 65 MODULE_DESCRIPTION("PF_CAN netlink gateway"); ··· 156 156 157 157 MODFUNC(mod_and_id, cf->can_id &= mod->modframe.and.can_id) 158 158 MODFUNC(mod_and_len, cf->len &= mod->modframe.and.len) 159 + MODFUNC(mod_and_flags, cf->flags &= mod->modframe.and.flags) 159 160 MODFUNC(mod_and_data, *(u64 *)cf->data &= *(u64 *)mod->modframe.and.data) 160 161 MODFUNC(mod_or_id, cf->can_id |= mod->modframe.or.can_id) 161 162 MODFUNC(mod_or_len, cf->len |= mod->modframe.or.len) 163 + MODFUNC(mod_or_flags, cf->flags |= mod->modframe.or.flags) 162 164 MODFUNC(mod_or_data, *(u64 *)cf->data |= *(u64 *)mod->modframe.or.data) 163 165 MODFUNC(mod_xor_id, cf->can_id ^= mod->modframe.xor.can_id) 164 166 MODFUNC(mod_xor_len, cf->len ^= mod->modframe.xor.len) 167 + MODFUNC(mod_xor_flags, cf->flags ^= mod->modframe.xor.flags) 165 168 MODFUNC(mod_xor_data, *(u64 *)cf->data ^= *(u64 *)mod->modframe.xor.data) 166 169 MODFUNC(mod_set_id, cf->can_id = mod->modframe.set.can_id) 167 170 MODFUNC(mod_set_len, cf->len = mod->modframe.set.len) 171 + MODFUNC(mod_set_flags, cf->flags = mod->modframe.set.flags) 168 172 MODFUNC(mod_set_data, *(u64 *)cf->data = *(u64 *)mod->modframe.set.data) 173 + 174 + static void mod_and_fddata(struct canfd_frame *cf, struct cf_mod *mod) 175 + { 176 + int i; 177 + 178 + for (i = 0; i < CANFD_MAX_DLEN; i += 8) 179 + *(u64 *)(cf->data + i) &= *(u64 *)(mod->modframe.and.data + i); 180 + } 181 + 182 + static void mod_or_fddata(struct canfd_frame *cf, struct cf_mod *mod) 183 + { 184 + int i; 185 + 186 + for (i = 0; i < CANFD_MAX_DLEN; i += 8) 187 + *(u64 *)(cf->data + i) |= *(u64 *)(mod->modframe.or.data + i); 188 + } 189 + 190 + static void mod_xor_fddata(struct canfd_frame *cf, struct cf_mod *mod) 191 + { 192 + int i; 193 + 194 + for (i = 0; i < CANFD_MAX_DLEN; i += 8) 195 + *(u64 *)(cf->data + i) ^= *(u64 *)(mod->modframe.xor.data + i); 196 + } 197 + 198 + static void mod_set_fddata(struct canfd_frame *cf, struct cf_mod *mod) 199 + { 200 + memcpy(cf->data, mod->modframe.set.data, CANFD_MAX_DLEN); 201 + } 169 202 170 203 static void canframecpy(struct canfd_frame *dst, struct can_frame *src) 171 204 { ··· 212 179 *(u64 *)dst->data = *(u64 *)src->data; 213 180 } 214 181 215 - static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re) 182 + static void canfdframecpy(struct canfd_frame *dst, struct canfd_frame *src) 183 + { 184 + /* Copy the struct members separately to ensure that no uninitialized 185 + * data are copied in the 2 bytes hole of the struct. This is needed 186 + * to make easy compares of the data in the struct cf_mod. 187 + */ 188 + 189 + dst->can_id = src->can_id; 190 + dst->flags = src->flags; 191 + dst->len = src->len; 192 + memcpy(dst->data, src->data, CANFD_MAX_DLEN); 193 + } 194 + 195 + static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re, struct rtcanmsg *r) 216 196 { 217 197 s8 dlen = CAN_MAX_DLEN; 198 + 199 + if (r->flags & CGW_FLAGS_CAN_FD) 200 + dlen = CANFD_MAX_DLEN; 218 201 219 202 /* absolute dlc values 0 .. 7 => 0 .. 7, e.g. data [0] 220 203 * relative to received dlc -1 .. -8 : ··· 400 351 struct sk_buff *nskb; 401 352 int modidx = 0; 402 353 354 + /* process strictly Classic CAN or CAN FD frames */ 355 + if (gwj->flags & CGW_FLAGS_CAN_FD) { 356 + if (skb->len != CANFD_MTU) 357 + return; 358 + } else { 359 + if (skb->len != CAN_MTU) 360 + return; 361 + } 362 + 403 363 /* Do not handle CAN frames routed more than 'max_hops' times. 404 364 * In general we should never catch this delimiter which is intended 405 365 * to cover a misconfiguration protection (e.g. circular CAN routes). ··· 477 419 int max_len = nskb->len - offsetof(struct canfd_frame, data); 478 420 479 421 /* dlc may have changed, make sure it fits to the CAN frame */ 480 - if (cf->len > max_len) 481 - goto out_delete; 422 + if (cf->len > max_len) { 423 + /* delete frame due to misconfiguration */ 424 + gwj->deleted_frames++; 425 + kfree_skb(nskb); 426 + return; 427 + } 482 428 483 - /* check for checksum updates in classic CAN length only */ 484 - if (gwj->mod.csumfunc.crc8) { 485 - if (cf->len > 8) 486 - goto out_delete; 487 - 429 + /* check for checksum updates */ 430 + if (gwj->mod.csumfunc.crc8) 488 431 (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8); 489 - } 490 432 491 - if (gwj->mod.csumfunc.xor) { 492 - if (cf->len > 8) 493 - goto out_delete; 494 - 433 + if (gwj->mod.csumfunc.xor) 495 434 (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor); 496 - } 497 435 } 498 436 499 437 /* clear the skb timestamp if not configured the other way */ ··· 501 447 gwj->dropped_frames++; 502 448 else 503 449 gwj->handled_frames++; 504 - 505 - return; 506 - 507 - out_delete: 508 - /* delete frame due to misconfiguration */ 509 - gwj->deleted_frames++; 510 - kfree_skb(nskb); 511 450 } 512 451 513 452 static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj) ··· 582 535 goto cancel; 583 536 } 584 537 585 - if (1) { 538 + if (gwj->flags & CGW_FLAGS_CAN_FD) { 539 + struct cgw_fdframe_mod mb; 540 + 541 + if (gwj->mod.modtype.and) { 542 + memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); 543 + mb.modtype = gwj->mod.modtype.and; 544 + if (nla_put(skb, CGW_FDMOD_AND, sizeof(mb), &mb) < 0) 545 + goto cancel; 546 + } 547 + 548 + if (gwj->mod.modtype.or) { 549 + memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf)); 550 + mb.modtype = gwj->mod.modtype.or; 551 + if (nla_put(skb, CGW_FDMOD_OR, sizeof(mb), &mb) < 0) 552 + goto cancel; 553 + } 554 + 555 + if (gwj->mod.modtype.xor) { 556 + memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf)); 557 + mb.modtype = gwj->mod.modtype.xor; 558 + if (nla_put(skb, CGW_FDMOD_XOR, sizeof(mb), &mb) < 0) 559 + goto cancel; 560 + } 561 + 562 + if (gwj->mod.modtype.set) { 563 + memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf)); 564 + mb.modtype = gwj->mod.modtype.set; 565 + if (nla_put(skb, CGW_FDMOD_SET, sizeof(mb), &mb) < 0) 566 + goto cancel; 567 + } 568 + } else { 586 569 struct cgw_frame_mod mb; 587 570 588 571 if (gwj->mod.modtype.and) { ··· 722 645 [CGW_FILTER] = { .len = sizeof(struct can_filter) }, 723 646 [CGW_LIM_HOPS] = { .type = NLA_U8 }, 724 647 [CGW_MOD_UID] = { .type = NLA_U32 }, 648 + [CGW_FDMOD_AND] = { .len = sizeof(struct cgw_fdframe_mod) }, 649 + [CGW_FDMOD_OR] = { .len = sizeof(struct cgw_fdframe_mod) }, 650 + [CGW_FDMOD_XOR] = { .len = sizeof(struct cgw_fdframe_mod) }, 651 + [CGW_FDMOD_SET] = { .len = sizeof(struct cgw_fdframe_mod) }, 725 652 }; 726 653 727 654 /* check for common and gwtype specific attributes */ ··· 733 652 u8 gwtype, void *gwtypeattr, u8 *limhops) 734 653 { 735 654 struct nlattr *tb[CGW_MAX + 1]; 655 + struct rtcanmsg *r = nlmsg_data(nlh); 736 656 int modidx = 0; 737 657 int err = 0; 738 658 ··· 753 671 } 754 672 755 673 /* check for AND/OR/XOR/SET modifications */ 756 - if (1) { 674 + if (r->flags & CGW_FLAGS_CAN_FD) { 675 + struct cgw_fdframe_mod mb; 676 + 677 + if (tb[CGW_FDMOD_AND]) { 678 + nla_memcpy(&mb, tb[CGW_FDMOD_AND], CGW_FDMODATTR_LEN); 679 + 680 + canfdframecpy(&mod->modframe.and, &mb.cf); 681 + mod->modtype.and = mb.modtype; 682 + 683 + if (mb.modtype & CGW_MOD_ID) 684 + mod->modfunc[modidx++] = mod_and_id; 685 + 686 + if (mb.modtype & CGW_MOD_LEN) 687 + mod->modfunc[modidx++] = mod_and_len; 688 + 689 + if (mb.modtype & CGW_MOD_FLAGS) 690 + mod->modfunc[modidx++] = mod_and_flags; 691 + 692 + if (mb.modtype & CGW_MOD_DATA) 693 + mod->modfunc[modidx++] = mod_and_fddata; 694 + } 695 + 696 + if (tb[CGW_FDMOD_OR]) { 697 + nla_memcpy(&mb, tb[CGW_FDMOD_OR], CGW_FDMODATTR_LEN); 698 + 699 + canfdframecpy(&mod->modframe.or, &mb.cf); 700 + mod->modtype.or = mb.modtype; 701 + 702 + if (mb.modtype & CGW_MOD_ID) 703 + mod->modfunc[modidx++] = mod_or_id; 704 + 705 + if (mb.modtype & CGW_MOD_LEN) 706 + mod->modfunc[modidx++] = mod_or_len; 707 + 708 + if (mb.modtype & CGW_MOD_FLAGS) 709 + mod->modfunc[modidx++] = mod_or_flags; 710 + 711 + if (mb.modtype & CGW_MOD_DATA) 712 + mod->modfunc[modidx++] = mod_or_fddata; 713 + } 714 + 715 + if (tb[CGW_FDMOD_XOR]) { 716 + nla_memcpy(&mb, tb[CGW_FDMOD_XOR], CGW_FDMODATTR_LEN); 717 + 718 + canfdframecpy(&mod->modframe.xor, &mb.cf); 719 + mod->modtype.xor = mb.modtype; 720 + 721 + if (mb.modtype & CGW_MOD_ID) 722 + mod->modfunc[modidx++] = mod_xor_id; 723 + 724 + if (mb.modtype & CGW_MOD_LEN) 725 + mod->modfunc[modidx++] = mod_xor_len; 726 + 727 + if (mb.modtype & CGW_MOD_FLAGS) 728 + mod->modfunc[modidx++] = mod_xor_flags; 729 + 730 + if (mb.modtype & CGW_MOD_DATA) 731 + mod->modfunc[modidx++] = mod_xor_fddata; 732 + } 733 + 734 + if (tb[CGW_FDMOD_SET]) { 735 + nla_memcpy(&mb, tb[CGW_FDMOD_SET], CGW_FDMODATTR_LEN); 736 + 737 + canfdframecpy(&mod->modframe.set, &mb.cf); 738 + mod->modtype.set = mb.modtype; 739 + 740 + if (mb.modtype & CGW_MOD_ID) 741 + mod->modfunc[modidx++] = mod_set_id; 742 + 743 + if (mb.modtype & CGW_MOD_LEN) 744 + mod->modfunc[modidx++] = mod_set_len; 745 + 746 + if (mb.modtype & CGW_MOD_FLAGS) 747 + mod->modfunc[modidx++] = mod_set_flags; 748 + 749 + if (mb.modtype & CGW_MOD_DATA) 750 + mod->modfunc[modidx++] = mod_set_fddata; 751 + } 752 + } else { 757 753 struct cgw_frame_mod mb; 758 754 759 755 if (tb[CGW_MOD_AND]) { ··· 905 745 struct cgw_csum_crc8 *c = nla_data(tb[CGW_CS_CRC8]); 906 746 907 747 err = cgw_chk_csum_parms(c->from_idx, c->to_idx, 908 - c->result_idx); 748 + c->result_idx, r); 909 749 if (err) 910 750 return err; 911 751 ··· 928 768 struct cgw_csum_xor *c = nla_data(tb[CGW_CS_XOR]); 929 769 930 770 err = cgw_chk_csum_parms(c->from_idx, c->to_idx, 931 - c->result_idx); 771 + c->result_idx, r); 932 772 if (err) 933 773 return err; 934 774