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

can: j1939: extend UAPI to notify about RX status

To be able to create applications with user friendly feedback, we need be
able to provide receive status information.

Typical ETP transfer may take seconds or even hours. To give user some
clue or show a progress bar, the stack should push status updates.
Same as for the TX information, the socket error queue will be used with
following new signals:
- J1939_EE_INFO_RX_RTS - received and accepted request to send signal.
- J1939_EE_INFO_RX_DPO - received data package offset signal
- J1939_EE_INFO_RX_ABORT - RX session was aborted

Instead of completion signal, user will get data package.
To activate this signals, application should set
SOF_TIMESTAMPING_RX_SOFTWARE to the SO_TIMESTAMPING socket option. This
will avoid unpredictable application behavior for the old software.

Link: https://lore.kernel.org/r/20210707094854.30781-3-o.rempel@pengutronix.de
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oleksij Rempel and committed by
Marc Kleine-Budde
5b9272e9 cd85d3ae

+136 -34
+9
include/uapi/linux/can/j1939.h
··· 78 78 enum { 79 79 J1939_NLA_PAD, 80 80 J1939_NLA_BYTES_ACKED, 81 + J1939_NLA_TOTAL_SIZE, 82 + J1939_NLA_PGN, 83 + J1939_NLA_SRC_NAME, 84 + J1939_NLA_DEST_NAME, 85 + J1939_NLA_SRC_ADDR, 86 + J1939_NLA_DEST_ADDR, 81 87 }; 82 88 83 89 enum { 84 90 J1939_EE_INFO_NONE, 85 91 J1939_EE_INFO_TX_ABORT, 92 + J1939_EE_INFO_RX_RTS, 93 + J1939_EE_INFO_RX_DPO, 94 + J1939_EE_INFO_RX_ABORT, 86 95 }; 87 96 88 97 struct j1939_filter {
+4
net/can/j1939/j1939-priv.h
··· 23 23 J1939_ERRQUEUE_TX_ACK, 24 24 J1939_ERRQUEUE_TX_SCHED, 25 25 J1939_ERRQUEUE_TX_ABORT, 26 + J1939_ERRQUEUE_RX_RTS, 27 + J1939_ERRQUEUE_RX_DPO, 28 + J1939_ERRQUEUE_RX_ABORT, 26 29 }; 27 30 28 31 /* j1939 devices */ ··· 90 87 struct list_head j1939_socks; 91 88 92 89 struct kref rx_kref; 90 + u32 rx_tskey; 93 91 }; 94 92 95 93 void j1939_ecu_put(struct j1939_ecu *ecu);
+105 -30
net/can/j1939/socket.c
··· 905 905 return NULL; 906 906 } 907 907 908 - static size_t j1939_sk_opt_stats_get_size(void) 908 + static size_t j1939_sk_opt_stats_get_size(enum j1939_sk_errqueue_type type) 909 909 { 910 - return 911 - nla_total_size(sizeof(u32)) + /* J1939_NLA_BYTES_ACKED */ 912 - 0; 910 + switch (type) { 911 + case J1939_ERRQUEUE_RX_RTS: 912 + return 913 + nla_total_size(sizeof(u32)) + /* J1939_NLA_TOTAL_SIZE */ 914 + nla_total_size(sizeof(u32)) + /* J1939_NLA_PGN */ 915 + nla_total_size(sizeof(u64)) + /* J1939_NLA_SRC_NAME */ 916 + nla_total_size(sizeof(u64)) + /* J1939_NLA_DEST_NAME */ 917 + nla_total_size(sizeof(u8)) + /* J1939_NLA_SRC_ADDR */ 918 + nla_total_size(sizeof(u8)) + /* J1939_NLA_DEST_ADDR */ 919 + 0; 920 + default: 921 + return 922 + nla_total_size(sizeof(u32)) + /* J1939_NLA_BYTES_ACKED */ 923 + 0; 924 + } 913 925 } 914 926 915 927 static struct sk_buff * 916 - j1939_sk_get_timestamping_opt_stats(struct j1939_session *session) 928 + j1939_sk_get_timestamping_opt_stats(struct j1939_session *session, 929 + enum j1939_sk_errqueue_type type) 917 930 { 918 931 struct sk_buff *stats; 919 932 u32 size; 920 933 921 - stats = alloc_skb(j1939_sk_opt_stats_get_size(), GFP_ATOMIC); 934 + stats = alloc_skb(j1939_sk_opt_stats_get_size(type), GFP_ATOMIC); 922 935 if (!stats) 923 936 return NULL; 924 937 ··· 941 928 size = min(session->pkt.tx_acked * 7, 942 929 session->total_message_size); 943 930 944 - nla_put_u32(stats, J1939_NLA_BYTES_ACKED, size); 931 + switch (type) { 932 + case J1939_ERRQUEUE_RX_RTS: 933 + nla_put_u32(stats, J1939_NLA_TOTAL_SIZE, 934 + session->total_message_size); 935 + nla_put_u32(stats, J1939_NLA_PGN, 936 + session->skcb.addr.pgn); 937 + nla_put_u64_64bit(stats, J1939_NLA_SRC_NAME, 938 + session->skcb.addr.src_name, J1939_NLA_PAD); 939 + nla_put_u64_64bit(stats, J1939_NLA_DEST_NAME, 940 + session->skcb.addr.dst_name, J1939_NLA_PAD); 941 + nla_put_u8(stats, J1939_NLA_SRC_ADDR, 942 + session->skcb.addr.sa); 943 + nla_put_u8(stats, J1939_NLA_DEST_ADDR, 944 + session->skcb.addr.da); 945 + break; 946 + default: 947 + nla_put_u32(stats, J1939_NLA_BYTES_ACKED, size); 948 + } 945 949 946 950 return stats; 947 951 } 948 952 949 - void j1939_sk_errqueue(struct j1939_session *session, 950 - enum j1939_sk_errqueue_type type) 953 + static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk, 954 + enum j1939_sk_errqueue_type type) 951 955 { 952 956 struct j1939_priv *priv = session->priv; 953 - struct sock *sk = session->sk; 954 957 struct j1939_sock *jsk; 955 958 struct sock_exterr_skb *serr; 956 959 struct sk_buff *skb; 957 960 char *state = "UNK"; 958 961 int err; 959 962 960 - /* currently we have no sk for the RX session */ 961 - if (!sk) 962 - return; 963 - 964 963 jsk = j1939_sk(sk); 965 964 966 965 if (!(jsk->state & J1939_SOCK_ERRQUEUE)) 967 966 return; 968 967 969 - skb = j1939_sk_get_timestamping_opt_stats(session); 968 + switch (type) { 969 + case J1939_ERRQUEUE_TX_ACK: 970 + if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK)) 971 + return; 972 + break; 973 + case J1939_ERRQUEUE_TX_SCHED: 974 + if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED)) 975 + return; 976 + break; 977 + case J1939_ERRQUEUE_TX_ABORT: 978 + break; 979 + case J1939_ERRQUEUE_RX_RTS: 980 + fallthrough; 981 + case J1939_ERRQUEUE_RX_DPO: 982 + fallthrough; 983 + case J1939_ERRQUEUE_RX_ABORT: 984 + if (!(sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE)) 985 + return; 986 + break; 987 + default: 988 + netdev_err(priv->ndev, "Unknown errqueue type %i\n", type); 989 + } 990 + 991 + skb = j1939_sk_get_timestamping_opt_stats(session, type); 970 992 if (!skb) 971 993 return; 972 994 ··· 1013 965 memset(serr, 0, sizeof(*serr)); 1014 966 switch (type) { 1015 967 case J1939_ERRQUEUE_TX_ACK: 1016 - if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK)) { 1017 - kfree_skb(skb); 1018 - return; 1019 - } 1020 - 1021 968 serr->ee.ee_errno = ENOMSG; 1022 969 serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; 1023 970 serr->ee.ee_info = SCM_TSTAMP_ACK; 1024 - state = "ACK"; 971 + state = "TX ACK"; 1025 972 break; 1026 973 case J1939_ERRQUEUE_TX_SCHED: 1027 - if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED)) { 1028 - kfree_skb(skb); 1029 - return; 1030 - } 1031 - 1032 974 serr->ee.ee_errno = ENOMSG; 1033 975 serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; 1034 976 serr->ee.ee_info = SCM_TSTAMP_SCHED; 1035 - state = "SCH"; 977 + state = "TX SCH"; 1036 978 break; 1037 979 case J1939_ERRQUEUE_TX_ABORT: 1038 980 serr->ee.ee_errno = session->err; 1039 981 serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL; 1040 982 serr->ee.ee_info = J1939_EE_INFO_TX_ABORT; 1041 - state = "ABT"; 983 + state = "TX ABT"; 1042 984 break; 1043 - default: 1044 - netdev_err(priv->ndev, "Unknown errqueue type %i\n", type); 985 + case J1939_ERRQUEUE_RX_RTS: 986 + serr->ee.ee_errno = ENOMSG; 987 + serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL; 988 + serr->ee.ee_info = J1939_EE_INFO_RX_RTS; 989 + state = "RX RTS"; 990 + break; 991 + case J1939_ERRQUEUE_RX_DPO: 992 + serr->ee.ee_errno = ENOMSG; 993 + serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL; 994 + serr->ee.ee_info = J1939_EE_INFO_RX_DPO; 995 + state = "RX DPO"; 996 + break; 997 + case J1939_ERRQUEUE_RX_ABORT: 998 + serr->ee.ee_errno = session->err; 999 + serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL; 1000 + serr->ee.ee_info = J1939_EE_INFO_RX_ABORT; 1001 + state = "RX ABT"; 1002 + break; 1045 1003 } 1046 1004 1047 1005 serr->opt_stats = true; ··· 1060 1006 1061 1007 if (err) 1062 1008 kfree_skb(skb); 1009 + }; 1010 + 1011 + void j1939_sk_errqueue(struct j1939_session *session, 1012 + enum j1939_sk_errqueue_type type) 1013 + { 1014 + struct j1939_priv *priv = session->priv; 1015 + struct j1939_sock *jsk; 1016 + 1017 + if (session->sk) { 1018 + /* send TX notifications to the socket of origin */ 1019 + __j1939_sk_errqueue(session, session->sk, type); 1020 + return; 1021 + } 1022 + 1023 + /* spread RX notifications to all sockets subscribed to this session */ 1024 + spin_lock_bh(&priv->j1939_socks_lock); 1025 + list_for_each_entry(jsk, &priv->j1939_socks, list) { 1026 + if (j1939_sk_recv_match_one(jsk, &session->skcb)) 1027 + __j1939_sk_errqueue(session, &jsk->sk, type); 1028 + } 1029 + spin_unlock_bh(&priv->j1939_socks_lock); 1063 1030 }; 1064 1031 1065 1032 void j1939_sk_send_loop_abort(struct sock *sk, int err)
+18 -4
net/can/j1939/transport.c
··· 260 260 261 261 static void j1939_session_destroy(struct j1939_session *session) 262 262 { 263 - if (session->err) 264 - j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_ABORT); 265 - else 266 - j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_ACK); 263 + if (session->transmission) { 264 + if (session->err) 265 + j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_ABORT); 266 + else 267 + j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_ACK); 268 + } else if (session->err) { 269 + j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT); 270 + } 267 271 268 272 netdev_dbg(session->priv->ndev, "%s: 0x%p\n", __func__, session); 269 273 ··· 1120 1116 1121 1117 if (session->sk) 1122 1118 j1939_sk_send_loop_abort(session->sk, session->err); 1119 + else 1120 + j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT); 1123 1121 } 1124 1122 1125 1123 static void j1939_session_cancel(struct j1939_session *session, ··· 1336 1330 session->err = j1939_xtp_abort_to_errno(priv, abort); 1337 1331 if (session->sk) 1338 1332 j1939_sk_send_loop_abort(session->sk, session->err); 1333 + else 1334 + j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT); 1339 1335 j1939_session_deactivate_activate_next(session); 1340 1336 1341 1337 abort_put: ··· 1638 1630 session->pkt.rx = 0; 1639 1631 session->pkt.tx = 0; 1640 1632 1633 + session->tskey = priv->rx_tskey++; 1634 + j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_RTS); 1635 + 1641 1636 WARN_ON_ONCE(j1939_session_activate(session)); 1642 1637 1643 1638 return session; ··· 1763 1752 session->pkt.dpo = j1939_etp_ctl_to_packet(skb->data); 1764 1753 session->last_cmd = dat[0]; 1765 1754 j1939_tp_set_rxtimeout(session, 750); 1755 + 1756 + if (!session->transmission) 1757 + j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_DPO); 1766 1758 } 1767 1759 1768 1760 static void j1939_xtp_rx_dpo(struct j1939_priv *priv, struct sk_buff *skb,