Skip to content

Commit 5b9272e

Browse files
oleremmarckleinebudde
authored andcommitted
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>
1 parent cd85d3a commit 5b9272e

File tree

4 files changed

+136
-34
lines changed

4 files changed

+136
-34
lines changed

include/uapi/linux/can/j1939.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,20 @@ enum {
7878
enum {
7979
J1939_NLA_PAD,
8080
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,
8187
};
8288

8389
enum {
8490
J1939_EE_INFO_NONE,
8591
J1939_EE_INFO_TX_ABORT,
92+
J1939_EE_INFO_RX_RTS,
93+
J1939_EE_INFO_RX_DPO,
94+
J1939_EE_INFO_RX_ABORT,
8695
};
8796

8897
struct j1939_filter {

net/can/j1939/j1939-priv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ enum j1939_sk_errqueue_type {
2323
J1939_ERRQUEUE_TX_ACK,
2424
J1939_ERRQUEUE_TX_SCHED,
2525
J1939_ERRQUEUE_TX_ABORT,
26+
J1939_ERRQUEUE_RX_RTS,
27+
J1939_ERRQUEUE_RX_DPO,
28+
J1939_ERRQUEUE_RX_ABORT,
2629
};
2730

2831
/* j1939 devices */
@@ -87,6 +90,7 @@ struct j1939_priv {
8790
struct list_head j1939_socks;
8891

8992
struct kref rx_kref;
93+
u32 rx_tskey;
9094
};
9195

9296
void j1939_ecu_put(struct j1939_ecu *ecu);

net/can/j1939/socket.c

Lines changed: 105 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -905,20 +905,33 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev,
905905
return NULL;
906906
}
907907

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)
909909
{
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+
}
913925
}
914926

915927
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)
917930
{
918931
struct sk_buff *stats;
919932
u32 size;
920933

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);
922935
if (!stats)
923936
return NULL;
924937

@@ -928,32 +941,67 @@ j1939_sk_get_timestamping_opt_stats(struct j1939_session *session)
928941
size = min(session->pkt.tx_acked * 7,
929942
session->total_message_size);
930943

931-
nla_put_u32(stats, J1939_NLA_BYTES_ACKED, size);
944+
switch (type) {
945+
case J1939_ERRQUEUE_RX_RTS:
946+
nla_put_u32(stats, J1939_NLA_TOTAL_SIZE,
947+
session->total_message_size);
948+
nla_put_u32(stats, J1939_NLA_PGN,
949+
session->skcb.addr.pgn);
950+
nla_put_u64_64bit(stats, J1939_NLA_SRC_NAME,
951+
session->skcb.addr.src_name, J1939_NLA_PAD);
952+
nla_put_u64_64bit(stats, J1939_NLA_DEST_NAME,
953+
session->skcb.addr.dst_name, J1939_NLA_PAD);
954+
nla_put_u8(stats, J1939_NLA_SRC_ADDR,
955+
session->skcb.addr.sa);
956+
nla_put_u8(stats, J1939_NLA_DEST_ADDR,
957+
session->skcb.addr.da);
958+
break;
959+
default:
960+
nla_put_u32(stats, J1939_NLA_BYTES_ACKED, size);
961+
}
932962

933963
return stats;
934964
}
935965

936-
void j1939_sk_errqueue(struct j1939_session *session,
937-
enum j1939_sk_errqueue_type type)
966+
static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk,
967+
enum j1939_sk_errqueue_type type)
938968
{
939969
struct j1939_priv *priv = session->priv;
940-
struct sock *sk = session->sk;
941970
struct j1939_sock *jsk;
942971
struct sock_exterr_skb *serr;
943972
struct sk_buff *skb;
944973
char *state = "UNK";
945974
int err;
946975

947-
/* currently we have no sk for the RX session */
948-
if (!sk)
949-
return;
950-
951976
jsk = j1939_sk(sk);
952977

953978
if (!(jsk->state & J1939_SOCK_ERRQUEUE))
954979
return;
955980

956-
skb = j1939_sk_get_timestamping_opt_stats(session);
981+
switch (type) {
982+
case J1939_ERRQUEUE_TX_ACK:
983+
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK))
984+
return;
985+
break;
986+
case J1939_ERRQUEUE_TX_SCHED:
987+
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED))
988+
return;
989+
break;
990+
case J1939_ERRQUEUE_TX_ABORT:
991+
break;
992+
case J1939_ERRQUEUE_RX_RTS:
993+
fallthrough;
994+
case J1939_ERRQUEUE_RX_DPO:
995+
fallthrough;
996+
case J1939_ERRQUEUE_RX_ABORT:
997+
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE))
998+
return;
999+
break;
1000+
default:
1001+
netdev_err(priv->ndev, "Unknown errqueue type %i\n", type);
1002+
}
1003+
1004+
skb = j1939_sk_get_timestamping_opt_stats(session, type);
9571005
if (!skb)
9581006
return;
9591007

@@ -965,35 +1013,41 @@ void j1939_sk_errqueue(struct j1939_session *session,
9651013
memset(serr, 0, sizeof(*serr));
9661014
switch (type) {
9671015
case J1939_ERRQUEUE_TX_ACK:
968-
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK)) {
969-
kfree_skb(skb);
970-
return;
971-
}
972-
9731016
serr->ee.ee_errno = ENOMSG;
9741017
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
9751018
serr->ee.ee_info = SCM_TSTAMP_ACK;
976-
state = "ACK";
1019+
state = "TX ACK";
9771020
break;
9781021
case J1939_ERRQUEUE_TX_SCHED:
979-
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED)) {
980-
kfree_skb(skb);
981-
return;
982-
}
983-
9841022
serr->ee.ee_errno = ENOMSG;
9851023
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
9861024
serr->ee.ee_info = SCM_TSTAMP_SCHED;
987-
state = "SCH";
1025+
state = "TX SCH";
9881026
break;
9891027
case J1939_ERRQUEUE_TX_ABORT:
9901028
serr->ee.ee_errno = session->err;
9911029
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
9921030
serr->ee.ee_info = J1939_EE_INFO_TX_ABORT;
993-
state = "ABT";
1031+
state = "TX ABT";
1032+
break;
1033+
case J1939_ERRQUEUE_RX_RTS:
1034+
serr->ee.ee_errno = ENOMSG;
1035+
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
1036+
serr->ee.ee_info = J1939_EE_INFO_RX_RTS;
1037+
state = "RX RTS";
1038+
break;
1039+
case J1939_ERRQUEUE_RX_DPO:
1040+
serr->ee.ee_errno = ENOMSG;
1041+
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
1042+
serr->ee.ee_info = J1939_EE_INFO_RX_DPO;
1043+
state = "RX DPO";
1044+
break;
1045+
case J1939_ERRQUEUE_RX_ABORT:
1046+
serr->ee.ee_errno = session->err;
1047+
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
1048+
serr->ee.ee_info = J1939_EE_INFO_RX_ABORT;
1049+
state = "RX ABT";
9941050
break;
995-
default:
996-
netdev_err(priv->ndev, "Unknown errqueue type %i\n", type);
9971051
}
9981052

9991053
serr->opt_stats = true;
@@ -1008,6 +1062,27 @@ void j1939_sk_errqueue(struct j1939_session *session,
10081062
kfree_skb(skb);
10091063
};
10101064

1065+
void j1939_sk_errqueue(struct j1939_session *session,
1066+
enum j1939_sk_errqueue_type type)
1067+
{
1068+
struct j1939_priv *priv = session->priv;
1069+
struct j1939_sock *jsk;
1070+
1071+
if (session->sk) {
1072+
/* send TX notifications to the socket of origin */
1073+
__j1939_sk_errqueue(session, session->sk, type);
1074+
return;
1075+
}
1076+
1077+
/* spread RX notifications to all sockets subscribed to this session */
1078+
spin_lock_bh(&priv->j1939_socks_lock);
1079+
list_for_each_entry(jsk, &priv->j1939_socks, list) {
1080+
if (j1939_sk_recv_match_one(jsk, &session->skcb))
1081+
__j1939_sk_errqueue(session, &jsk->sk, type);
1082+
}
1083+
spin_unlock_bh(&priv->j1939_socks_lock);
1084+
};
1085+
10111086
void j1939_sk_send_loop_abort(struct sock *sk, int err)
10121087
{
10131088
sk->sk_err = err;

net/can/j1939/transport.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,14 @@ static void __j1939_session_drop(struct j1939_session *session)
260260

261261
static void j1939_session_destroy(struct j1939_session *session)
262262
{
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+
}
267271

268272
netdev_dbg(session->priv->ndev, "%s: 0x%p\n", __func__, session);
269273

@@ -1116,6 +1120,8 @@ static void __j1939_session_cancel(struct j1939_session *session,
11161120

11171121
if (session->sk)
11181122
j1939_sk_send_loop_abort(session->sk, session->err);
1123+
else
1124+
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
11191125
}
11201126

11211127
static void j1939_session_cancel(struct j1939_session *session,
@@ -1330,6 +1336,8 @@ static void j1939_xtp_rx_abort_one(struct j1939_priv *priv, struct sk_buff *skb,
13301336
session->err = j1939_xtp_abort_to_errno(priv, abort);
13311337
if (session->sk)
13321338
j1939_sk_send_loop_abort(session->sk, session->err);
1339+
else
1340+
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
13331341
j1939_session_deactivate_activate_next(session);
13341342

13351343
abort_put:
@@ -1630,6 +1638,9 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv,
16301638
session->pkt.rx = 0;
16311639
session->pkt.tx = 0;
16321640

1641+
session->tskey = priv->rx_tskey++;
1642+
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_RTS);
1643+
16331644
WARN_ON_ONCE(j1939_session_activate(session));
16341645

16351646
return session;
@@ -1752,6 +1763,9 @@ static void j1939_xtp_rx_dpo_one(struct j1939_session *session,
17521763
session->pkt.dpo = j1939_etp_ctl_to_packet(skb->data);
17531764
session->last_cmd = dat[0];
17541765
j1939_tp_set_rxtimeout(session, 750);
1766+
1767+
if (!session->transmission)
1768+
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_DPO);
17551769
}
17561770

17571771
static void j1939_xtp_rx_dpo(struct j1939_priv *priv, struct sk_buff *skb,

0 commit comments

Comments
 (0)