summaryrefslogtreecommitdiffstats
path: root/net/can
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2019-08-10 15:18:10 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2019-08-13 11:32:21 -0400
commit456a8a646b2563438c16a9b27decf9aa717f1ebb (patch)
tree4af45d1dc678b1479a13915bfc9c306961b0d9e9 /net/can
parente9dc7c60507c822992e793bd3845f0556ae0ff98 (diff)
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>
Diffstat (limited to 'net/can')
-rw-r--r--net/can/gw.c214
1 files changed, 187 insertions, 27 deletions
diff --git a/net/can/gw.c b/net/can/gw.c
index 3a1ad206fbef..65d60c93af29 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 1// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
2/* gw.c - CAN frame Gateway/Router/Bridge with netlink interface 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 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
@@ -59,7 +59,7 @@
59#include <net/net_namespace.h> 59#include <net/net_namespace.h>
60#include <net/sock.h> 60#include <net/sock.h>
61 61
62#define CAN_GW_VERSION "20170425" 62#define CAN_GW_VERSION "20190810"
63#define CAN_GW_NAME "can-gw" 63#define CAN_GW_NAME "can-gw"
64 64
65MODULE_DESCRIPTION("PF_CAN netlink gateway"); 65MODULE_DESCRIPTION("PF_CAN netlink gateway");
@@ -156,17 +156,50 @@ struct cgw_job {
156 156
157MODFUNC(mod_and_id, cf->can_id &= mod->modframe.and.can_id) 157MODFUNC(mod_and_id, cf->can_id &= mod->modframe.and.can_id)
158MODFUNC(mod_and_len, cf->len &= mod->modframe.and.len) 158MODFUNC(mod_and_len, cf->len &= mod->modframe.and.len)
159MODFUNC(mod_and_flags, cf->flags &= mod->modframe.and.flags)
159MODFUNC(mod_and_data, *(u64 *)cf->data &= *(u64 *)mod->modframe.and.data) 160MODFUNC(mod_and_data, *(u64 *)cf->data &= *(u64 *)mod->modframe.and.data)
160MODFUNC(mod_or_id, cf->can_id |= mod->modframe.or.can_id) 161MODFUNC(mod_or_id, cf->can_id |= mod->modframe.or.can_id)
161MODFUNC(mod_or_len, cf->len |= mod->modframe.or.len) 162MODFUNC(mod_or_len, cf->len |= mod->modframe.or.len)
163MODFUNC(mod_or_flags, cf->flags |= mod->modframe.or.flags)
162MODFUNC(mod_or_data, *(u64 *)cf->data |= *(u64 *)mod->modframe.or.data) 164MODFUNC(mod_or_data, *(u64 *)cf->data |= *(u64 *)mod->modframe.or.data)
163MODFUNC(mod_xor_id, cf->can_id ^= mod->modframe.xor.can_id) 165MODFUNC(mod_xor_id, cf->can_id ^= mod->modframe.xor.can_id)
164MODFUNC(mod_xor_len, cf->len ^= mod->modframe.xor.len) 166MODFUNC(mod_xor_len, cf->len ^= mod->modframe.xor.len)
167MODFUNC(mod_xor_flags, cf->flags ^= mod->modframe.xor.flags)
165MODFUNC(mod_xor_data, *(u64 *)cf->data ^= *(u64 *)mod->modframe.xor.data) 168MODFUNC(mod_xor_data, *(u64 *)cf->data ^= *(u64 *)mod->modframe.xor.data)
166MODFUNC(mod_set_id, cf->can_id = mod->modframe.set.can_id) 169MODFUNC(mod_set_id, cf->can_id = mod->modframe.set.can_id)
167MODFUNC(mod_set_len, cf->len = mod->modframe.set.len) 170MODFUNC(mod_set_len, cf->len = mod->modframe.set.len)
171MODFUNC(mod_set_flags, cf->flags = mod->modframe.set.flags)
168MODFUNC(mod_set_data, *(u64 *)cf->data = *(u64 *)mod->modframe.set.data) 172MODFUNC(mod_set_data, *(u64 *)cf->data = *(u64 *)mod->modframe.set.data)
169 173
174static 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
182static 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
190static 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
198static 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}
202
170static void canframecpy(struct canfd_frame *dst, struct can_frame *src) 203static void canframecpy(struct canfd_frame *dst, struct can_frame *src)
171{ 204{
172 /* Copy the struct members separately to ensure that no uninitialized 205 /* Copy the struct members separately to ensure that no uninitialized
@@ -179,10 +212,26 @@ static void canframecpy(struct canfd_frame *dst, struct can_frame *src)
179 *(u64 *)dst->data = *(u64 *)src->data; 212 *(u64 *)dst->data = *(u64 *)src->data;
180} 213}
181 214
182static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re) 215static void canfdframecpy(struct canfd_frame *dst, struct canfd_frame *src)
216{
217 /* Copy the struct members separately to ensure that no uninitialized
218 * data are copied in the 2 bytes hole of the struct. This is needed
219 * to make easy compares of the data in the struct cf_mod.
220 */
221
222 dst->can_id = src->can_id;
223 dst->flags = src->flags;
224 dst->len = src->len;
225 memcpy(dst->data, src->data, CANFD_MAX_DLEN);
226}
227
228static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re, struct rtcanmsg *r)
183{ 229{
184 s8 dlen = CAN_MAX_DLEN; 230 s8 dlen = CAN_MAX_DLEN;
185 231
232 if (r->flags & CGW_FLAGS_CAN_FD)
233 dlen = CANFD_MAX_DLEN;
234
186 /* absolute dlc values 0 .. 7 => 0 .. 7, e.g. data [0] 235 /* absolute dlc values 0 .. 7 => 0 .. 7, e.g. data [0]
187 * relative to received dlc -1 .. -8 : 236 * relative to received dlc -1 .. -8 :
188 * e.g. for received dlc = 8 237 * e.g. for received dlc = 8
@@ -351,6 +400,15 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
351 struct sk_buff *nskb; 400 struct sk_buff *nskb;
352 int modidx = 0; 401 int modidx = 0;
353 402
403 /* process strictly Classic CAN or CAN FD frames */
404 if (gwj->flags & CGW_FLAGS_CAN_FD) {
405 if (skb->len != CANFD_MTU)
406 return;
407 } else {
408 if (skb->len != CAN_MTU)
409 return;
410 }
411
354 /* Do not handle CAN frames routed more than 'max_hops' times. 412 /* Do not handle CAN frames routed more than 'max_hops' times.
355 * In general we should never catch this delimiter which is intended 413 * In general we should never catch this delimiter which is intended
356 * to cover a misconfiguration protection (e.g. circular CAN routes). 414 * to cover a misconfiguration protection (e.g. circular CAN routes).
@@ -419,23 +477,19 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
419 int max_len = nskb->len - offsetof(struct canfd_frame, data); 477 int max_len = nskb->len - offsetof(struct canfd_frame, data);
420 478
421 /* dlc may have changed, make sure it fits to the CAN frame */ 479 /* dlc may have changed, make sure it fits to the CAN frame */
422 if (cf->len > max_len) 480 if (cf->len > max_len) {
423 goto out_delete; 481 /* delete frame due to misconfiguration */
424 482 gwj->deleted_frames++;
425 /* check for checksum updates in classic CAN length only */ 483 kfree_skb(nskb);
426 if (gwj->mod.csumfunc.crc8) { 484 return;
427 if (cf->len > 8)
428 goto out_delete;
429
430 (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8);
431 } 485 }
432 486
433 if (gwj->mod.csumfunc.xor) { 487 /* check for checksum updates */
434 if (cf->len > 8) 488 if (gwj->mod.csumfunc.crc8)
435 goto out_delete; 489 (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8);
436 490
491 if (gwj->mod.csumfunc.xor)
437 (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor); 492 (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor);
438 }
439 } 493 }
440 494
441 /* clear the skb timestamp if not configured the other way */ 495 /* clear the skb timestamp if not configured the other way */
@@ -447,13 +501,6 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
447 gwj->dropped_frames++; 501 gwj->dropped_frames++;
448 else 502 else
449 gwj->handled_frames++; 503 gwj->handled_frames++;
450
451 return;
452
453 out_delete:
454 /* delete frame due to misconfiguration */
455 gwj->deleted_frames++;
456 kfree_skb(nskb);
457} 504}
458 505
459static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj) 506static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
@@ -535,7 +582,37 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
535 goto cancel; 582 goto cancel;
536 } 583 }
537 584
538 if (1) { 585 if (gwj->flags & CGW_FLAGS_CAN_FD) {
586 struct cgw_fdframe_mod mb;
587
588 if (gwj->mod.modtype.and) {
589 memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
590 mb.modtype = gwj->mod.modtype.and;
591 if (nla_put(skb, CGW_FDMOD_AND, sizeof(mb), &mb) < 0)
592 goto cancel;
593 }
594
595 if (gwj->mod.modtype.or) {
596 memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf));
597 mb.modtype = gwj->mod.modtype.or;
598 if (nla_put(skb, CGW_FDMOD_OR, sizeof(mb), &mb) < 0)
599 goto cancel;
600 }
601
602 if (gwj->mod.modtype.xor) {
603 memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf));
604 mb.modtype = gwj->mod.modtype.xor;
605 if (nla_put(skb, CGW_FDMOD_XOR, sizeof(mb), &mb) < 0)
606 goto cancel;
607 }
608
609 if (gwj->mod.modtype.set) {
610 memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf));
611 mb.modtype = gwj->mod.modtype.set;
612 if (nla_put(skb, CGW_FDMOD_SET, sizeof(mb), &mb) < 0)
613 goto cancel;
614 }
615 } else {
539 struct cgw_frame_mod mb; 616 struct cgw_frame_mod mb;
540 617
541 if (gwj->mod.modtype.and) { 618 if (gwj->mod.modtype.and) {
@@ -645,6 +722,10 @@ static const struct nla_policy cgw_policy[CGW_MAX + 1] = {
645 [CGW_FILTER] = { .len = sizeof(struct can_filter) }, 722 [CGW_FILTER] = { .len = sizeof(struct can_filter) },
646 [CGW_LIM_HOPS] = { .type = NLA_U8 }, 723 [CGW_LIM_HOPS] = { .type = NLA_U8 },
647 [CGW_MOD_UID] = { .type = NLA_U32 }, 724 [CGW_MOD_UID] = { .type = NLA_U32 },
725 [CGW_FDMOD_AND] = { .len = sizeof(struct cgw_fdframe_mod) },
726 [CGW_FDMOD_OR] = { .len = sizeof(struct cgw_fdframe_mod) },
727 [CGW_FDMOD_XOR] = { .len = sizeof(struct cgw_fdframe_mod) },
728 [CGW_FDMOD_SET] = { .len = sizeof(struct cgw_fdframe_mod) },
648}; 729};
649 730
650/* check for common and gwtype specific attributes */ 731/* check for common and gwtype specific attributes */
@@ -652,6 +733,7 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
652 u8 gwtype, void *gwtypeattr, u8 *limhops) 733 u8 gwtype, void *gwtypeattr, u8 *limhops)
653{ 734{
654 struct nlattr *tb[CGW_MAX + 1]; 735 struct nlattr *tb[CGW_MAX + 1];
736 struct rtcanmsg *r = nlmsg_data(nlh);
655 int modidx = 0; 737 int modidx = 0;
656 int err = 0; 738 int err = 0;
657 739
@@ -671,7 +753,85 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
671 } 753 }
672 754
673 /* check for AND/OR/XOR/SET modifications */ 755 /* check for AND/OR/XOR/SET modifications */
674 if (1) { 756 if (r->flags & CGW_FLAGS_CAN_FD) {
757 struct cgw_fdframe_mod mb;
758
759 if (tb[CGW_FDMOD_AND]) {
760 nla_memcpy(&mb, tb[CGW_FDMOD_AND], CGW_FDMODATTR_LEN);
761
762 canfdframecpy(&mod->modframe.and, &mb.cf);
763 mod->modtype.and = mb.modtype;
764
765 if (mb.modtype & CGW_MOD_ID)
766 mod->modfunc[modidx++] = mod_and_id;
767
768 if (mb.modtype & CGW_MOD_LEN)
769 mod->modfunc[modidx++] = mod_and_len;
770
771 if (mb.modtype & CGW_MOD_FLAGS)
772 mod->modfunc[modidx++] = mod_and_flags;
773
774 if (mb.modtype & CGW_MOD_DATA)
775 mod->modfunc[modidx++] = mod_and_fddata;
776 }
777
778 if (tb[CGW_FDMOD_OR]) {
779 nla_memcpy(&mb, tb[CGW_FDMOD_OR], CGW_FDMODATTR_LEN);
780
781 canfdframecpy(&mod->modframe.or, &mb.cf);
782 mod->modtype.or = mb.modtype;
783
784 if (mb.modtype & CGW_MOD_ID)
785 mod->modfunc[modidx++] = mod_or_id;
786
787 if (mb.modtype & CGW_MOD_LEN)
788 mod->modfunc[modidx++] = mod_or_len;
789
790 if (mb.modtype & CGW_MOD_FLAGS)
791 mod->modfunc[modidx++] = mod_or_flags;
792
793 if (mb.modtype & CGW_MOD_DATA)
794 mod->modfunc[modidx++] = mod_or_fddata;
795 }
796
797 if (tb[CGW_FDMOD_XOR]) {
798 nla_memcpy(&mb, tb[CGW_FDMOD_XOR], CGW_FDMODATTR_LEN);
799
800 canfdframecpy(&mod->modframe.xor, &mb.cf);
801 mod->modtype.xor = mb.modtype;
802
803 if (mb.modtype & CGW_MOD_ID)
804 mod->modfunc[modidx++] = mod_xor_id;
805
806 if (mb.modtype & CGW_MOD_LEN)
807 mod->modfunc[modidx++] = mod_xor_len;
808
809 if (mb.modtype & CGW_MOD_FLAGS)
810 mod->modfunc[modidx++] = mod_xor_flags;
811
812 if (mb.modtype & CGW_MOD_DATA)
813 mod->modfunc[modidx++] = mod_xor_fddata;
814 }
815
816 if (tb[CGW_FDMOD_SET]) {
817 nla_memcpy(&mb, tb[CGW_FDMOD_SET], CGW_FDMODATTR_LEN);
818
819 canfdframecpy(&mod->modframe.set, &mb.cf);
820 mod->modtype.set = mb.modtype;
821
822 if (mb.modtype & CGW_MOD_ID)
823 mod->modfunc[modidx++] = mod_set_id;
824
825 if (mb.modtype & CGW_MOD_LEN)
826 mod->modfunc[modidx++] = mod_set_len;
827
828 if (mb.modtype & CGW_MOD_FLAGS)
829 mod->modfunc[modidx++] = mod_set_flags;
830
831 if (mb.modtype & CGW_MOD_DATA)
832 mod->modfunc[modidx++] = mod_set_fddata;
833 }
834 } else {
675 struct cgw_frame_mod mb; 835 struct cgw_frame_mod mb;
676 836
677 if (tb[CGW_MOD_AND]) { 837 if (tb[CGW_MOD_AND]) {
@@ -745,7 +905,7 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
745 struct cgw_csum_crc8 *c = nla_data(tb[CGW_CS_CRC8]); 905 struct cgw_csum_crc8 *c = nla_data(tb[CGW_CS_CRC8]);
746 906
747 err = cgw_chk_csum_parms(c->from_idx, c->to_idx, 907 err = cgw_chk_csum_parms(c->from_idx, c->to_idx,
748 c->result_idx); 908 c->result_idx, r);
749 if (err) 909 if (err)
750 return err; 910 return err;
751 911
@@ -768,7 +928,7 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
768 struct cgw_csum_xor *c = nla_data(tb[CGW_CS_XOR]); 928 struct cgw_csum_xor *c = nla_data(tb[CGW_CS_XOR]);
769 929
770 err = cgw_chk_csum_parms(c->from_idx, c->to_idx, 930 err = cgw_chk_csum_parms(c->from_idx, c->to_idx,
771 c->result_idx); 931 c->result_idx, r);
772 if (err) 932 if (err)
773 return err; 933 return err;
774 934