2019.04.27 v2: - make MSG_ERRQUEUE optional and disabled by default - init info struct in sendmsg - add verbose TX status support. 2019.04.25 v1: With this patches user space application is able to track the status of (E)TP transfers. If this option is needed, application should construct control message with PKTINFO->cookie set to some value (for example pointer or sequence number). To get transmit status, application should use recvmsg(..., MSG_ERRQUEUE). As response it will get PKTINFO->cookie and error value if transfer was aborted. On success error is set to zero. This example can be used to send data with attached control message and cookie. static ssize_t jcat_sendto_flags(int fd, void *buf, size_t buf_size, int flags, struct sockaddr *dest_addr, socklen_t addrlen, __u64 cookie) { struct msghdr msgheader; struct cmsghdr *control_msg; struct iovec msg_iov; char control_buf[256]; struct j1939_pktinfo *info; ssize_t count; /* Set up iov and msgheader */ memset(&msgheader, 0, sizeof(struct msghdr)); msg_iov.iov_base = buf; msg_iov.iov_len = buf_size; msgheader.msg_name = dest_addr; msgheader.msg_namelen = addrlen; msgheader.msg_iov = &msg_iov; msgheader.msg_iovlen = 1; msgheader.msg_flags = 0; msgheader.msg_control = control_buf; msgheader.msg_controllen = sizeof(control_buf); control_msg = CMSG_FIRSTHDR(&msgheader); control_msg->cmsg_level = SOL_CAN_J1939; control_msg->cmsg_type = SCM_J1939_PKTINFO; control_msg->cmsg_len = CMSG_LEN(sizeof(*info)); info = (struct j1939_pktinfo *)CMSG_DATA(control_msg); memset(info, 0, sizeof(*info)); info->cookie = cookie; msgheader.msg_controllen = control_msg->cmsg_len; if (((count = sendmsg(fd, &msgheader, flags))) < 0) error(1, errno, "sendmsg error"); return count; } This example can be used to receive transfer status report. static int jcat_recv_err(struct jcat_priv *priv) { struct sock_extended_err *serr; struct msghdr msg = {}; struct iovec iov[1]; struct j1939_pktinfo info; struct cmsghdr *cm; int ret; char control[100]; iov[0].iov_base = &info; iov[0].iov_len = sizeof(info); msg.msg_iov = iov ; msg.msg_iovlen = 1 ; msg.msg_control = control; msg.msg_controllen = sizeof(control); ret = recvmsg(priv->sock, &msg, MSG_ERRQUEUE); if (ret == -1 && errno == EAGAIN) return false; if (ret == -1) error(1, errno, "recvmsg notification: %i", errno); if (msg.msg_flags & MSG_CTRUNC) error(1, errno, "recvmsg notification: truncated"); cm = CMSG_FIRSTHDR(&msg); if (!cm) error(1, 0, "cmsg: no cmsg"); if (!(cm->cmsg_level == SOL_CAN_J1939 && cm->cmsg_type == SCM_J1939_RECVERR)) error(1, 0, "serr: wrong type: %d.%d", cm->cmsg_level, cm->cmsg_type); serr = (void *) CMSG_DATA(cm); if (serr->ee_origin != SO_EE_ORIGIN_TXSTATUS) error(1, 0, "serr: wrong origin: %u", serr->ee_origin); if (serr->ee_errno) warnx("serr: tx error: %i, %s", serr->ee_errno, strerror(serr->ee_errno)); warnx("pktinfo: cookie: 0x%llx", info.cookie); return serr->ee_errno; } Oleksij Rempel (2): j1939: add MSG_ERRQUEUE support j1939: check supported recv*() flags include/uapi/linux/can/j1939.h | 10 +++ net/can/j1939/j1939-priv.h | 5 ++ net/can/j1939/socket.c | 118 +++++++++++++++++++++++++++++++-- net/can/j1939/transport.c | 11 ++- 4 files changed, 137 insertions(+), 7 deletions(-) -- 2.20.1