Skip to content

Commit 0231811

Browse files
committed
can: isotp: add support for transmission without flow control
JIRA: https://issues.redhat.com/browse/RHEL-80832 commit 9f39d36 Author: Oliver Hartkopp <socketcan@hartkopp.net> Date: Sat May 7 13:55:58 2022 +0200 can: isotp: add support for transmission without flow control Usually the ISO 15765-2 protocol is a point-to-point protocol to transfer segmented PDUs to a dedicated receiver. This receiver sends a flow control message to specify protocol options and timings (e.g. block size / STmin). The so called functional addressing communication allows a 1:N communication but is limited to a single frame length. This new CAN_ISOTP_CF_BROADCAST allows an unconfirmed 1:N communication with PDU length that would not fit into a single frame. This feature is not covered by the ISO 15765-2 standard. Link: https://lore.kernel.org/all/20220507115558.19065-1-socketcan@hartkopp.net Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Radu Rendec <rrendec@redhat.com>
1 parent 59eb228 commit 0231811

File tree

2 files changed

+92
-33
lines changed

2 files changed

+92
-33
lines changed

include/uapi/linux/can/isotp.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,19 @@ struct can_isotp_ll_options {
124124

125125
/* flags for isotp behaviour */
126126

127-
#define CAN_ISOTP_LISTEN_MODE 0x001 /* listen only (do not send FC) */
128-
#define CAN_ISOTP_EXTEND_ADDR 0x002 /* enable extended addressing */
129-
#define CAN_ISOTP_TX_PADDING 0x004 /* enable CAN frame padding tx path */
130-
#define CAN_ISOTP_RX_PADDING 0x008 /* enable CAN frame padding rx path */
131-
#define CAN_ISOTP_CHK_PAD_LEN 0x010 /* check received CAN frame padding */
132-
#define CAN_ISOTP_CHK_PAD_DATA 0x020 /* check received CAN frame padding */
133-
#define CAN_ISOTP_HALF_DUPLEX 0x040 /* half duplex error state handling */
134-
#define CAN_ISOTP_FORCE_TXSTMIN 0x080 /* ignore stmin from received FC */
135-
#define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */
136-
#define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */
137-
#define CAN_ISOTP_WAIT_TX_DONE 0x400 /* wait for tx completion */
138-
#define CAN_ISOTP_SF_BROADCAST 0x800 /* 1-to-N functional addressing */
127+
#define CAN_ISOTP_LISTEN_MODE 0x0001 /* listen only (do not send FC) */
128+
#define CAN_ISOTP_EXTEND_ADDR 0x0002 /* enable extended addressing */
129+
#define CAN_ISOTP_TX_PADDING 0x0004 /* enable CAN frame padding tx path */
130+
#define CAN_ISOTP_RX_PADDING 0x0008 /* enable CAN frame padding rx path */
131+
#define CAN_ISOTP_CHK_PAD_LEN 0x0010 /* check received CAN frame padding */
132+
#define CAN_ISOTP_CHK_PAD_DATA 0x0020 /* check received CAN frame padding */
133+
#define CAN_ISOTP_HALF_DUPLEX 0x0040 /* half duplex error state handling */
134+
#define CAN_ISOTP_FORCE_TXSTMIN 0x0080 /* ignore stmin from received FC */
135+
#define CAN_ISOTP_FORCE_RXSTMIN 0x0100 /* ignore CFs depending on rx stmin */
136+
#define CAN_ISOTP_RX_EXT_ADDR 0x0200 /* different rx extended addressing */
137+
#define CAN_ISOTP_WAIT_TX_DONE 0x0400 /* wait for tx completion */
138+
#define CAN_ISOTP_SF_BROADCAST 0x0800 /* 1-to-N functional addressing */
139+
#define CAN_ISOTP_CF_BROADCAST 0x1000 /* 1-to-N transmission w/o FC */
139140

140141
/* protocol machine default values */
141142

net/can/isotp.c

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ MODULE_ALIAS("can-proto-6");
103103
#define FC_CONTENT_SZ 3 /* flow control content size in byte (FS/BS/STmin) */
104104

105105
#define ISOTP_CHECK_PADDING (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA)
106+
#define ISOTP_ALL_BC_FLAGS (CAN_ISOTP_SF_BROADCAST | CAN_ISOTP_CF_BROADCAST)
106107

107108
/* Flow Status given in FC frame */
108109
#define ISOTP_FC_CTS 0 /* clear to send */
@@ -157,6 +158,23 @@ static inline struct isotp_sock *isotp_sk(const struct sock *sk)
157158
return (struct isotp_sock *)sk;
158159
}
159160

161+
static u32 isotp_bc_flags(struct isotp_sock *so)
162+
{
163+
return so->opt.flags & ISOTP_ALL_BC_FLAGS;
164+
}
165+
166+
static bool isotp_register_rxid(struct isotp_sock *so)
167+
{
168+
/* no broadcast modes => register rx_id for FC frame reception */
169+
return (isotp_bc_flags(so) == 0);
170+
}
171+
172+
static bool isotp_register_txecho(struct isotp_sock *so)
173+
{
174+
/* all modes but SF_BROADCAST register for tx echo skbs */
175+
return (isotp_bc_flags(so) != CAN_ISOTP_SF_BROADCAST);
176+
}
177+
160178
static enum hrtimer_restart isotp_rx_timer_handler(struct hrtimer *hrtimer)
161179
{
162180
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
@@ -792,7 +810,6 @@ static void isotp_create_fframe(struct canfd_frame *cf, struct isotp_sock *so,
792810
cf->data[i] = so->tx.buf[so->tx.idx++];
793811

794812
so->tx.sn = 1;
795-
so->tx.state = ISOTP_WAIT_FIRST_FC;
796813
}
797814

798815
static void isotp_rcv_echo(struct sk_buff *skb, void *data)
@@ -925,7 +942,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
925942
off = (so->tx.ll_dl > CAN_MAX_DLEN) ? 1 : 0;
926943

927944
/* does the given data fit into a single frame for SF_BROADCAST? */
928-
if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) &&
945+
if ((isotp_bc_flags(so) == CAN_ISOTP_SF_BROADCAST) &&
929946
(size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) {
930947
err = -EINVAL;
931948
goto err_out_drop;
@@ -989,12 +1006,41 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
9891006
/* don't enable wait queue for a single frame transmission */
9901007
wait_tx_done = 0;
9911008
} else {
992-
/* send first frame and wait for FC */
1009+
/* send first frame */
9931010

9941011
isotp_create_fframe(cf, so, ae);
9951012

996-
/* start timeout for FC */
997-
hrtimer_sec = 1;
1013+
if (isotp_bc_flags(so) == CAN_ISOTP_CF_BROADCAST) {
1014+
/* set timer for FC-less operation (STmin = 0) */
1015+
if (so->opt.flags & CAN_ISOTP_FORCE_TXSTMIN)
1016+
so->tx_gap = ktime_set(0, so->force_tx_stmin);
1017+
else
1018+
so->tx_gap = ktime_set(0, so->frame_txtime);
1019+
1020+
/* disable wait for FCs due to activated block size */
1021+
so->txfc.bs = 0;
1022+
1023+
/* cfecho should have been zero'ed by init */
1024+
if (so->cfecho)
1025+
pr_notice_once("can-isotp: no fc cfecho %08X\n",
1026+
so->cfecho);
1027+
1028+
/* set consecutive frame echo tag */
1029+
so->cfecho = *(u32 *)cf->data;
1030+
1031+
/* switch directly to ISOTP_SENDING state */
1032+
so->tx.state = ISOTP_SENDING;
1033+
1034+
/* start timeout for unlikely lost echo skb */
1035+
hrtimer_sec = 2;
1036+
} else {
1037+
/* standard flow control check */
1038+
so->tx.state = ISOTP_WAIT_FIRST_FC;
1039+
1040+
/* start timeout for FC */
1041+
hrtimer_sec = 1;
1042+
}
1043+
9981044
hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0),
9991045
HRTIMER_MODE_REL_SOFT);
10001046
}
@@ -1014,6 +1060,9 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
10141060
if (hrtimer_sec)
10151061
hrtimer_cancel(&so->txtimer);
10161062

1063+
/* reset consecutive frame echo tag */
1064+
so->cfecho = 0;
1065+
10171066
goto err_out_drop;
10181067
}
10191068

@@ -1110,15 +1159,17 @@ static int isotp_release(struct socket *sock)
11101159
lock_sock(sk);
11111160

11121161
/* remove current filters & unregister */
1113-
if (so->bound && (!(so->opt.flags & CAN_ISOTP_SF_BROADCAST))) {
1162+
if (so->bound && isotp_register_txecho(so)) {
11141163
if (so->ifindex) {
11151164
struct net_device *dev;
11161165

11171166
dev = dev_get_by_index(net, so->ifindex);
11181167
if (dev) {
1119-
can_rx_unregister(net, dev, so->rxid,
1120-
SINGLE_MASK(so->rxid),
1121-
isotp_rcv, sk);
1168+
if (isotp_register_rxid(so))
1169+
can_rx_unregister(net, dev, so->rxid,
1170+
SINGLE_MASK(so->rxid),
1171+
isotp_rcv, sk);
1172+
11221173
can_rx_unregister(net, dev, so->txid,
11231174
SINGLE_MASK(so->txid),
11241175
isotp_rcv_echo, sk);
@@ -1154,7 +1205,6 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
11541205
canid_t tx_id, rx_id;
11551206
int err = 0;
11561207
int notify_enetdown = 0;
1157-
int do_rx_reg = 1;
11581208

11591209
if (len < ISOTP_MIN_NAMELEN)
11601210
return -EINVAL;
@@ -1187,12 +1237,8 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
11871237
goto out;
11881238
}
11891239

1190-
/* do not register frame reception for functional addressing */
1191-
if (so->opt.flags & CAN_ISOTP_SF_BROADCAST)
1192-
do_rx_reg = 0;
1193-
1194-
/* do not validate rx address for functional addressing */
1195-
if (do_rx_reg && rx_id == tx_id) {
1240+
/* ensure different CAN IDs when the rx_id is to be registered */
1241+
if (isotp_register_rxid(so) && rx_id == tx_id) {
11961242
err = -EADDRNOTAVAIL;
11971243
goto out;
11981244
}
@@ -1217,10 +1263,11 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
12171263

12181264
ifindex = dev->ifindex;
12191265

1220-
if (do_rx_reg) {
1266+
if (isotp_register_rxid(so))
12211267
can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id),
12221268
isotp_rcv, sk, "isotp", sk);
12231269

1270+
if (isotp_register_txecho(so)) {
12241271
/* no consecutive frame echo skb in flight */
12251272
so->cfecho = 0;
12261273

@@ -1289,6 +1336,15 @@ static int isotp_setsockopt_locked(struct socket *sock, int level, int optname,
12891336
if (!(so->opt.flags & CAN_ISOTP_RX_EXT_ADDR))
12901337
so->opt.rx_ext_address = so->opt.ext_address;
12911338

1339+
/* these broadcast flags are not allowed together */
1340+
if (isotp_bc_flags(so) == ISOTP_ALL_BC_FLAGS) {
1341+
/* CAN_ISOTP_SF_BROADCAST is prioritized */
1342+
so->opt.flags &= ~CAN_ISOTP_CF_BROADCAST;
1343+
1344+
/* give user feedback on wrong config attempt */
1345+
ret = -EINVAL;
1346+
}
1347+
12921348
/* check for frame_txtime changes (0 => no changes) */
12931349
if (so->opt.frame_txtime) {
12941350
if (so->opt.frame_txtime == CAN_ISOTP_FRAME_TXTIME_ZERO)
@@ -1439,10 +1495,12 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
14391495
case NETDEV_UNREGISTER:
14401496
lock_sock(sk);
14411497
/* remove current filters & unregister */
1442-
if (so->bound && (!(so->opt.flags & CAN_ISOTP_SF_BROADCAST))) {
1443-
can_rx_unregister(dev_net(dev), dev, so->rxid,
1444-
SINGLE_MASK(so->rxid),
1445-
isotp_rcv, sk);
1498+
if (so->bound && isotp_register_txecho(so)) {
1499+
if (isotp_register_rxid(so))
1500+
can_rx_unregister(dev_net(dev), dev, so->rxid,
1501+
SINGLE_MASK(so->rxid),
1502+
isotp_rcv, sk);
1503+
14461504
can_rx_unregister(dev_net(dev), dev, so->txid,
14471505
SINGLE_MASK(so->txid),
14481506
isotp_rcv_echo, sk);

0 commit comments

Comments
 (0)