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

can: isotp: add SF_BROADCAST support for functional addressing

When CAN_ISOTP_SF_BROADCAST is set in the CAN_ISOTP_OPTS flags the CAN_ISOTP
socket is switched into functional addressing mode, where only single frame
(SF) protocol data units can be send on the specified CAN interface and the
given tp.tx_id after bind().

In opposite to normal and extended addressing this socket does not register a
CAN-ID for reception which would be needed for a 1-to-1 ISOTP connection with a
segmented bi-directional data transfer.

Sending SFs on this socket is therefore a TX-only 'broadcast' operation.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Thomas Wagner <thwa1@web.de>
Link: https://lore.kernel.org/r/20201206144731.4609-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
921ca574 a7105e34

+30 -14
+1 -1
include/uapi/linux/can/isotp.h
··· 135 135 #define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */ 136 136 #define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */ 137 137 #define CAN_ISOTP_WAIT_TX_DONE 0x400 /* wait for tx completion */ 138 - 138 + #define CAN_ISOTP_SF_BROADCAST 0x800 /* 1-to-N functional addressing */ 139 139 140 140 /* default values */ 141 141
+29 -13
net/can/isotp.c
··· 865 865 if (!size || size > MAX_MSG_LENGTH) 866 866 return -EINVAL; 867 867 868 + /* take care of a potential SF_DL ESC offset for TX_DL > 8 */ 869 + off = (so->tx.ll_dl > CAN_MAX_DLEN) ? 1 : 0; 870 + 871 + /* does the given data fit into a single frame for SF_BROADCAST? */ 872 + if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) && 873 + (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) 874 + return -EINVAL; 875 + 868 876 err = memcpy_from_msg(so->tx.buf, msg, size); 869 877 if (err < 0) 870 878 return err; ··· 898 890 899 891 cf = (struct canfd_frame *)skb->data; 900 892 skb_put(skb, so->ll.mtu); 901 - 902 - /* take care of a potential SF_DL ESC offset for TX_DL > 8 */ 903 - off = (so->tx.ll_dl > CAN_MAX_DLEN) ? 1 : 0; 904 893 905 894 /* check for single frame transmission depending on TX_DL */ 906 895 if (size <= so->tx.ll_dl - SF_PCI_SZ4 - ae - off) { ··· 1021 1016 hrtimer_cancel(&so->rxtimer); 1022 1017 1023 1018 /* remove current filters & unregister */ 1024 - if (so->bound) { 1019 + if (so->bound && (!(so->opt.flags & CAN_ISOTP_SF_BROADCAST))) { 1025 1020 if (so->ifindex) { 1026 1021 struct net_device *dev; 1027 1022 ··· 1057 1052 struct net_device *dev; 1058 1053 int err = 0; 1059 1054 int notify_enetdown = 0; 1055 + int do_rx_reg = 1; 1060 1056 1061 1057 if (len < CAN_REQUIRED_SIZE(struct sockaddr_can, can_addr.tp)) 1062 1058 return -EINVAL; 1063 1059 1064 - if (addr->can_addr.tp.rx_id == addr->can_addr.tp.tx_id) 1065 - return -EADDRNOTAVAIL; 1060 + /* do not register frame reception for functional addressing */ 1061 + if (so->opt.flags & CAN_ISOTP_SF_BROADCAST) 1062 + do_rx_reg = 0; 1066 1063 1067 - if ((addr->can_addr.tp.rx_id | addr->can_addr.tp.tx_id) & 1068 - (CAN_ERR_FLAG | CAN_RTR_FLAG)) 1064 + /* do not validate rx address for functional addressing */ 1065 + if (do_rx_reg) { 1066 + if (addr->can_addr.tp.rx_id == addr->can_addr.tp.tx_id) 1067 + return -EADDRNOTAVAIL; 1068 + 1069 + if (addr->can_addr.tp.rx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) 1070 + return -EADDRNOTAVAIL; 1071 + } 1072 + 1073 + if (addr->can_addr.tp.tx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) 1069 1074 return -EADDRNOTAVAIL; 1070 1075 1071 1076 if (!addr->can_ifindex) ··· 1108 1093 1109 1094 ifindex = dev->ifindex; 1110 1095 1111 - can_rx_register(net, dev, addr->can_addr.tp.rx_id, 1112 - SINGLE_MASK(addr->can_addr.tp.rx_id), isotp_rcv, sk, 1113 - "isotp", sk); 1096 + if (do_rx_reg) 1097 + can_rx_register(net, dev, addr->can_addr.tp.rx_id, 1098 + SINGLE_MASK(addr->can_addr.tp.rx_id), 1099 + isotp_rcv, sk, "isotp", sk); 1114 1100 1115 1101 dev_put(dev); 1116 1102 1117 - if (so->bound) { 1103 + if (so->bound && do_rx_reg) { 1118 1104 /* unregister old filter */ 1119 1105 if (so->ifindex) { 1120 1106 dev = dev_get_by_index(net, so->ifindex); ··· 1315 1299 case NETDEV_UNREGISTER: 1316 1300 lock_sock(sk); 1317 1301 /* remove current filters & unregister */ 1318 - if (so->bound) 1302 + if (so->bound && (!(so->opt.flags & CAN_ISOTP_SF_BROADCAST))) 1319 1303 can_rx_unregister(dev_net(dev), dev, so->rxid, 1320 1304 SINGLE_MASK(so->rxid), 1321 1305 isotp_rcv, sk);