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

Configure Feed

Select the types of activity you want to include in your feed.

can: canxl: add virtual CAN network identifier support

CAN XL data frames contain an 8-bit virtual CAN network identifier (VCID).
A VCID value of zero represents an 'untagged' CAN XL frame.

To receive and send these optional VCIDs via CAN_RAW sockets a new socket
option CAN_RAW_XL_VCID_OPTS is introduced to define/access VCID content:

- tx: set the outgoing VCID value by the kernel (one fixed 8-bit value)
- tx: pass through VCID values from the user space (e.g. for traffic replay)
- rx: apply VCID receive filter (value/mask) to be passed to the user space

With the 'tx pass through' option CAN_RAW_XL_VCID_TX_PASS all valid VCID
values can be sent, e.g. to replay full qualified CAN XL traffic.

The VCID value provided for the CAN_RAW_XL_VCID_TX_SET option will
override the VCID value in the struct canxl_frame.prio defined for
CAN_RAW_XL_VCID_TX_PASS when both flags are set.

With a rx_vcid_mask of zero all possible VCID values (0x00 - 0xFF) are
passed to the user space when the CAN_RAW_XL_VCID_RX_FILTER flag is set.
Without this flag only untagged CAN XL frames (VCID = 0x00) are delivered
to the user space (default).

The 8-bit VCID is stored inside the CAN XL prio element (only in CAN XL
frames!) to not interfere with other CAN content or the CAN filters
provided by the CAN_RAW sockets and kernel infrastruture.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/all/20240212213550.18516-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
c83c22ec 383de566

+110 -10
+7 -2
include/uapi/linux/can.h
··· 193 193 #define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */ 194 194 #define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */ 195 195 196 + /* the 8-bit VCID is optionally placed in the canxl_frame.prio element */ 197 + #define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */ 198 + #define CANXL_VCID_VAL_MASK 0xFFUL /* VCID is an 8-bit value */ 199 + #define CANXL_VCID_MASK (CANXL_VCID_VAL_MASK << CANXL_VCID_OFFSET) 200 + 196 201 /** 197 202 * struct canxl_frame - CAN with e'X'tended frame 'L'ength frame structure 198 - * @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags 203 + * @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags / VCID 199 204 * @flags: additional flags for CAN XL 200 205 * @sdt: SDU (service data unit) type 201 206 * @len: frame payload length in byte (CANXL_MIN_DLEN .. CANXL_MAX_DLEN) ··· 210 205 * @prio shares the same position as @can_id from struct can[fd]_frame. 211 206 */ 212 207 struct canxl_frame { 213 - canid_t prio; /* 11 bit priority for arbitration (canid_t) */ 208 + canid_t prio; /* 11 bit priority for arbitration / 8 bit VCID */ 214 209 __u8 flags; /* additional flags for CAN XL */ 215 210 __u8 sdt; /* SDU (service data unit) type */ 216 211 __u16 len; /* frame payload length in byte */
+16
include/uapi/linux/can/raw.h
··· 65 65 CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ 66 66 CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ 67 67 CAN_RAW_XL_FRAMES, /* allow CAN XL frames (default:off) */ 68 + CAN_RAW_XL_VCID_OPTS, /* CAN XL VCID configuration options */ 68 69 }; 70 + 71 + /* configuration for CAN XL virtual CAN identifier (VCID) handling */ 72 + struct can_raw_vcid_options { 73 + 74 + __u8 flags; /* flags for vcid (filter) behaviour */ 75 + __u8 tx_vcid; /* VCID value set into canxl_frame.prio */ 76 + __u8 rx_vcid; /* VCID value for VCID filter */ 77 + __u8 rx_vcid_mask; /* VCID mask for VCID filter */ 78 + 79 + }; 80 + 81 + /* can_raw_vcid_options.flags for CAN XL virtual CAN identifier handling */ 82 + #define CAN_RAW_XL_VCID_TX_SET 0x01 83 + #define CAN_RAW_XL_VCID_TX_PASS 0x02 84 + #define CAN_RAW_XL_VCID_RX_FILTER 0x04 69 85 70 86 #endif /* !_UAPI_CAN_RAW_H */
+2
net/can/af_can.c
··· 865 865 /* check for correct padding to be able to use the structs similarly */ 866 866 BUILD_BUG_ON(offsetof(struct can_frame, len) != 867 867 offsetof(struct canfd_frame, len) || 868 + offsetof(struct can_frame, len) != 869 + offsetof(struct canxl_frame, flags) || 868 870 offsetof(struct can_frame, data) != 869 871 offsetof(struct canfd_frame, data)); 870 872
+85 -8
net/can/raw.c
··· 91 91 int recv_own_msgs; 92 92 int fd_frames; 93 93 int xl_frames; 94 + struct can_raw_vcid_options raw_vcid_opts; 95 + canid_t tx_vcid_shifted; 96 + canid_t rx_vcid_shifted; 97 + canid_t rx_vcid_mask_shifted; 94 98 int join_filters; 95 99 int count; /* number of active filters */ 96 100 struct can_filter dfilter; /* default/single filter */ ··· 138 134 return; 139 135 140 136 /* make sure to not pass oversized frames to the socket */ 141 - if ((!ro->fd_frames && can_is_canfd_skb(oskb)) || 142 - (!ro->xl_frames && can_is_canxl_skb(oskb))) 137 + if (!ro->fd_frames && can_is_canfd_skb(oskb)) 143 138 return; 139 + 140 + if (can_is_canxl_skb(oskb)) { 141 + struct canxl_frame *cxl = (struct canxl_frame *)oskb->data; 142 + 143 + /* make sure to not pass oversized frames to the socket */ 144 + if (!ro->xl_frames) 145 + return; 146 + 147 + /* filter CAN XL VCID content */ 148 + if (ro->raw_vcid_opts.flags & CAN_RAW_XL_VCID_RX_FILTER) { 149 + /* apply VCID filter if user enabled the filter */ 150 + if ((cxl->prio & ro->rx_vcid_mask_shifted) != 151 + (ro->rx_vcid_shifted & ro->rx_vcid_mask_shifted)) 152 + return; 153 + } else { 154 + /* no filter => do not forward VCID tagged frames */ 155 + if (cxl->prio & CANXL_VCID_MASK) 156 + return; 157 + } 158 + } 144 159 145 160 /* eliminate multiple filter matches for the same skb */ 146 161 if (this_cpu_ptr(ro->uniq)->skb == oskb && ··· 721 698 ro->fd_frames = ro->xl_frames; 722 699 break; 723 700 701 + case CAN_RAW_XL_VCID_OPTS: 702 + if (optlen != sizeof(ro->raw_vcid_opts)) 703 + return -EINVAL; 704 + 705 + if (copy_from_sockptr(&ro->raw_vcid_opts, optval, optlen)) 706 + return -EFAULT; 707 + 708 + /* prepare 32 bit values for handling in hot path */ 709 + ro->tx_vcid_shifted = ro->raw_vcid_opts.tx_vcid << CANXL_VCID_OFFSET; 710 + ro->rx_vcid_shifted = ro->raw_vcid_opts.rx_vcid << CANXL_VCID_OFFSET; 711 + ro->rx_vcid_mask_shifted = ro->raw_vcid_opts.rx_vcid_mask << CANXL_VCID_OFFSET; 712 + break; 713 + 724 714 case CAN_RAW_JOIN_FILTERS: 725 715 if (optlen != sizeof(ro->join_filters)) 726 716 return -EINVAL; ··· 822 786 val = &ro->xl_frames; 823 787 break; 824 788 789 + case CAN_RAW_XL_VCID_OPTS: 790 + /* user space buffer to small for VCID opts? */ 791 + if (len < sizeof(ro->raw_vcid_opts)) { 792 + /* return -ERANGE and needed space in optlen */ 793 + err = -ERANGE; 794 + if (put_user(sizeof(ro->raw_vcid_opts), optlen)) 795 + err = -EFAULT; 796 + } else { 797 + if (len > sizeof(ro->raw_vcid_opts)) 798 + len = sizeof(ro->raw_vcid_opts); 799 + if (copy_to_user(optval, &ro->raw_vcid_opts, len)) 800 + err = -EFAULT; 801 + } 802 + break; 803 + 825 804 case CAN_RAW_JOIN_FILTERS: 826 805 if (len > sizeof(int)) 827 806 len = sizeof(int); ··· 854 803 return 0; 855 804 } 856 805 857 - static bool raw_bad_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu) 806 + static void raw_put_canxl_vcid(struct raw_sock *ro, struct sk_buff *skb) 807 + { 808 + struct canxl_frame *cxl = (struct canxl_frame *)skb->data; 809 + 810 + /* sanitize non CAN XL bits */ 811 + cxl->prio &= (CANXL_PRIO_MASK | CANXL_VCID_MASK); 812 + 813 + /* clear VCID in CAN XL frame if pass through is disabled */ 814 + if (!(ro->raw_vcid_opts.flags & CAN_RAW_XL_VCID_TX_PASS)) 815 + cxl->prio &= CANXL_PRIO_MASK; 816 + 817 + /* set VCID in CAN XL frame if enabled */ 818 + if (ro->raw_vcid_opts.flags & CAN_RAW_XL_VCID_TX_SET) { 819 + cxl->prio &= CANXL_PRIO_MASK; 820 + cxl->prio |= ro->tx_vcid_shifted; 821 + } 822 + } 823 + 824 + static unsigned int raw_check_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu) 858 825 { 859 826 /* Classical CAN -> no checks for flags and device capabilities */ 860 827 if (can_is_can_skb(skb)) 861 - return false; 828 + return CAN_MTU; 862 829 863 830 /* CAN FD -> needs to be enabled and a CAN FD or CAN XL device */ 864 831 if (ro->fd_frames && can_is_canfd_skb(skb) && 865 832 (mtu == CANFD_MTU || can_is_canxl_dev_mtu(mtu))) 866 - return false; 833 + return CANFD_MTU; 867 834 868 835 /* CAN XL -> needs to be enabled and a CAN XL device */ 869 836 if (ro->xl_frames && can_is_canxl_skb(skb) && 870 837 can_is_canxl_dev_mtu(mtu)) 871 - return false; 838 + return CANXL_MTU; 872 839 873 - return true; 840 + return 0; 874 841 } 875 842 876 843 static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ··· 898 829 struct sockcm_cookie sockc; 899 830 struct sk_buff *skb; 900 831 struct net_device *dev; 832 + unsigned int txmtu; 901 833 int ifindex; 902 834 int err = -EINVAL; 903 835 ··· 939 869 goto free_skb; 940 870 941 871 err = -EINVAL; 942 - if (raw_bad_txframe(ro, skb, dev->mtu)) 872 + 873 + /* check for valid CAN (CC/FD/XL) frame content */ 874 + txmtu = raw_check_txframe(ro, skb, dev->mtu); 875 + if (!txmtu) 943 876 goto free_skb; 877 + 878 + /* only CANXL: clear/forward/set VCID value */ 879 + if (txmtu == CANXL_MTU) 880 + raw_put_canxl_vcid(ro, skb); 944 881 945 882 sockcm_init(&sockc, sk); 946 883 if (msg->msg_controllen) {