From 06d3beb08ca55dfa3c33401d7542fad1d3e48898 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 4 Apr 2019 10:17:27 +0200 Subject: [PATCH 1/7] include: import header files from linux-5.0 (including new j1939 patches) Signed-off-by: Marc Kleine-Budde --- include/linux/can.h | 7 ++----- include/linux/can/j1939.h | 9 +++++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/linux/can.h b/include/linux/can.h index 6248566..4e46a7e 100644 --- a/include/linux/can.h +++ b/include/linux/can.h @@ -77,7 +77,7 @@ typedef __u32 canid_t; /* * Controller Area Network Error Message Frame Mask structure * - * bit 0-28 : error class mask (see include/linux/can/error.h) + * bit 0-28 : error class mask (see include/uapi/linux/can/error.h) * bit 29-31 : set to zero */ typedef __u32 can_err_mask_t; @@ -181,10 +181,7 @@ struct sockaddr_can { int can_ifindex; union { /* transport protocol class address information (e.g. ISOTP) */ - struct { - canid_t rx_id; - canid_t tx_id; - } tp; + struct { canid_t rx_id, tx_id; } tp; /* J1939 address information */ struct { diff --git a/include/linux/can/j1939.h b/include/linux/can/j1939.h index 3063806..cd60d70 100644 --- a/include/linux/can/j1939.h +++ b/include/linux/can/j1939.h @@ -16,9 +16,14 @@ #include #include -#define J1939_IDLE_ADDR 0xfe -#define J1939_NO_ADDR 0xff +#define J1939_IDLE_ADDR 0xfe +#define J1939_MAX_UNICAST_ADDR 0xfd +#define J1939_NO_ADDR 0xff /* == broadcast or no addr */ #define J1939_NO_NAME 0 +#define J1939_PGN_REQUEST 0x0ea00 +#define J1939_PGN_ADDRESS_CLAIMED 0x0ee00 +#define J1939_PGN_PDU1_MAX 0x3ff00 +#define J1939_PGN_MAX 0x3ffff #define J1939_NO_PGN 0x40000 /* J1939 Parameter Group Number From 314f8a92ae79b0880f7c4d506576a780102d938d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 14 Mar 2019 11:50:44 +0100 Subject: [PATCH 2/7] j1939: use defines instead of magic values for now cover most of PGN values. Signed-off-by: Oleksij Rempel Signed-off-by: Marc Kleine-Budde --- jacd.c | 22 +++++++++++----------- jspy.c | 2 +- libj1939.c | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/jacd.c b/jacd.c index 0970520..aa5898f 100644 --- a/jacd.c +++ b/jacd.c @@ -175,14 +175,14 @@ static int parse_range(char *str) /* j1939 socket */ static const struct j1939_filter filt[] = { { - .pgn = 0x0ee00, - .pgn_mask = 0x3ff00, + .pgn = J1939_PGN_ADDRESS_CLAIMED, + .pgn_mask = J1939_PGN_PDU1_MAX, }, { - .pgn = 0x0ea00, - .pgn_mask = 0x3ff00, + .pgn = J1939_PGN_REQUEST, + .pgn_mask = J1939_PGN_PDU1_MAX, }, { .pgn = 0x0fed8, - .pgn_mask = 0x3ffff, + .pgn_mask = J1939_PGN_MAX, }, }; @@ -195,7 +195,7 @@ static int open_socket(const char *device, uint64_t name) .can_addr.j1939 = { .name = name, .addr = J1939_IDLE_ADDR, - .pgn = 0x0ee00, + .pgn = J1939_NO_PGN, }, .can_ifindex = if_nametoindex(s.intf), }; @@ -260,7 +260,7 @@ static int claim_address(int sock, uint64_t name, int sa) .can_addr.j1939 = { .name = name, .addr = sa, - .pgn = 0x0ee00, + .pgn = J1939_NO_PGN, }, .can_ifindex = if_nametoindex(s.intf), }; @@ -280,7 +280,7 @@ static int request_addresses(int sock) int ret; static const struct sockaddr_can saddr = { .can_family = AF_CAN, - .can_addr.j1939.pgn = 0x0ea00, + .can_addr.j1939.pgn = J1939_PGN_REQUEST, .can_addr.j1939.addr = J1939_NO_ADDR, }; @@ -569,11 +569,11 @@ int main(int argc, char *argv[]) error(1, errno, "recvfrom()"); } switch (saddr.can_addr.j1939.pgn) { - case 0x0ea00: + case J1939_PGN_REQUEST: if (ret < 3) break; pgn = dat[0] + (dat[1] << 8) + ((dat[2] & 0x03) << 16); - if (pgn != 0x0ee00) + if (pgn != J1939_PGN_ADDRESS_CLAIMED) /* not interested */ break; if (s.state == STATE_REQ_SENT) { @@ -587,7 +587,7 @@ int main(int argc, char *argv[]) schedule_itimer(50); } break; - case 0x0ee00: + case J1939_PGN_ADDRESS_CLAIMED: if (saddr.can_addr.j1939.addr >= J1939_IDLE_ADDR) { sa = lookup_name(saddr.can_addr.j1939.name); if (sa < J1939_IDLE_ADDR) diff --git a/jspy.c b/jspy.c index 55ddeb7..5764be5 100644 --- a/jspy.c +++ b/jspy.c @@ -162,7 +162,7 @@ int main(int argc, char **argv) filt.addr_mask = ~0; ++filter; } - if (s.addr.can_addr.j1939.pgn <= 0x3ffff) { + if (s.addr.can_addr.j1939.pgn <= J1939_PGN_MAX) { filt.pgn = s.addr.can_addr.j1939.pgn; filt.pgn_mask = ~0; ++filter; diff --git a/libj1939.c b/libj1939.c index 9bb6fe5..002bebd 100644 --- a/libj1939.c +++ b/libj1939.c @@ -183,13 +183,13 @@ const char *libj1939_addr2str(const struct sockaddr_can *can) } if (can->can_addr.j1939.name) { str += sprintf(str, "%016llx", (unsigned long long)can->can_addr.j1939.name); - if (can->can_addr.j1939.pgn == 0x0ee00) + if (can->can_addr.j1939.pgn == J1939_PGN_ADDRESS_CLAIMED) str += sprintf(str, ".%02x", can->can_addr.j1939.addr); } else if (can->can_addr.j1939.addr <= 0xfe) str += sprintf(str, "%02x", can->can_addr.j1939.addr); else str += sprintf(str, "-"); - if (can->can_addr.j1939.pgn <= 0x3ffff) + if (can->can_addr.j1939.pgn <= J1939_PGN_MAX) str += sprintf(str, ",%05x", can->can_addr.j1939.pgn); return buf; From b8a2fa319a57adc909c4e785e800ff2f4d014807 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 13 Mar 2019 06:27:50 +0100 Subject: [PATCH 3/7] jacd: use sendto instead of send Accordint to the new UAPI version, bind() with PGN set, should not be used for destination PGN. This change should work with new and old version of UAPI. Signed-off-by: Oleksij Rempel Signed-off-by: Marc Kleine-Budde --- jacd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/jacd.c b/jacd.c index aa5898f..0f4d5e5 100644 --- a/jacd.c +++ b/jacd.c @@ -241,13 +241,21 @@ static int repeat_address(int sock, uint64_t name) { int ret; uint8_t dat[8]; + static const struct sockaddr_can saddr = { + .can_family = AF_CAN, + .can_addr.j1939 = { + .pgn = J1939_PGN_ADDRESS_CLAIMED, + .addr = J1939_NO_ADDR, + }, + }; memcpy(dat, &name, 8); if (!host_is_little_endian()) bswap(dat, 8); if (s.verbose) fprintf(stderr, "- send(, %" PRId64 ", 8, 0);\n", name); - ret = send(sock, dat, 8, 0); + ret = sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr, + sizeof(saddr)); if (must_warn(ret)) error(1, errno, "send address claim for 0x%02x", s.last_sa); return ret; From 7192b0b9d7c97e91099b523902740d1b1df91cb8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 21 Mar 2019 15:33:26 +0100 Subject: [PATCH 4/7] jacd: set SO_BROADCAST with latest UAPI version we should set this flag to be allowed to send broadcast frames with broadcast destination address. Even if on CAN every thing is a broadcast... Signed-off-by: Oleksij Rempel Signed-off-by: Marc Kleine-Budde --- jacd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/jacd.c b/jacd.c index 0f4d5e5..a1a53d6 100644 --- a/jacd.c +++ b/jacd.c @@ -228,6 +228,14 @@ static int open_socket(const char *device, uint64_t name) if (ret < 0) error(1, errno, "setsockopt receive own msgs"); + value = 1; + if (s.verbose) + fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_BROADCAST, %d, %zd);\n", value, sizeof(value)); + ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, + &value, sizeof(value)); + if (ret < 0) + error(1, errno, "setsockopt set broadcast"); + if (s.verbose) fprintf(stderr, "- bind(, %s, %zi);\n", libj1939_addr2str(&saddr), sizeof(saddr)); ret = bind(sock, (void *)&saddr, sizeof(saddr)); From b931fb514c118b091a3077460ae0ec1dbe1b4a9d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 4 Apr 2019 10:38:01 +0200 Subject: [PATCH 5/7] jcat: add missing close of outfile and j1939 socket Signed-off-by: Oleksij Rempel Signed-off-by: Marc Kleine-Budde --- jcat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jcat.c b/jcat.c index 304a0dc..8b4c644 100644 --- a/jcat.c +++ b/jcat.c @@ -364,6 +364,8 @@ int main(int argc, char *argv[]) ret = jcat_send(priv); close(priv->infile); + close(priv->outfile); + close(priv->sock); return ret; } From 48a4a4bef44009cb5235e408cf28f111045ed29f Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 22 Mar 2019 09:18:33 +0100 Subject: [PATCH 6/7] jcat: user recv() instead of recvfrom() No information from recvfrom() is currently used. So, it is enough to use plain recv(). Signed-off-by: Oleksij Rempel Signed-off-by: Marc Kleine-Budde --- jcat.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/jcat.c b/jcat.c index 8b4c644..92c4f53 100644 --- a/jcat.c +++ b/jcat.c @@ -199,14 +199,11 @@ static int jcat_send(struct jcat_priv *priv) static int jcat_recv_one(struct jcat_priv *priv, uint8_t *buf, size_t buf_size) { - socklen_t peernamelen; int ret; - peernamelen = sizeof(priv->peername); - ret = recvfrom(priv->sock, buf, buf_size, 0, - (void *)&priv->peername, &peernamelen); + ret = recv(priv->sock, buf, buf_size, 0); if (ret < 0) { - warn("recvfrom()"); + warn("recvf()"); return EXIT_FAILURE; } From 19d41bec457bcfb9c85d0ddfb53c5403967bb3ff Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 22 Mar 2019 09:16:45 +0100 Subject: [PATCH 7/7] jcat: allow to re-send rest of the buffer if we was interrupted latest version of UAPI allows to continue sending on some signals. Signed-off-by: Oleksij Rempel --- jcat.c | 159 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 119 insertions(+), 40 deletions(-) diff --git a/jcat.c b/jcat.c index 92c4f53..c299c31 100644 --- a/jcat.c +++ b/jcat.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "libj1939.h" #define J1939_MAX_ETP_PACKET_SIZE (7 * 0x00ffffff) @@ -34,7 +35,7 @@ struct jcat_priv { int sock; int infile; int outfile; - unsigned int todo_send; + size_t max_transfer; int todo_prio; bool valid_peername; @@ -42,6 +43,8 @@ struct jcat_priv { bool todo_filesize; bool todo_connect; + unsigned long polltimeout; + struct sockaddr_can sockname; struct sockaddr_can peername; }; @@ -52,8 +55,10 @@ static const char help_msg[] = " FROM / TO - or [IFACE][:[SA][,[PGN][,NAME]]]\n" "Options:\n" " -i (default stdin)\n" - " -s[=LEN] Initial send of LEN bytes dummy data\n" + " -s Set maximal transfer size. Default: 117440505 byte\n" " -r Receive data\n" + " -P poll timeout in milliseconds before sending data.\n" + " With this option send() will be used with MSG_DONTWAIT flag.\n" "\n" "Example:\n" "jcat -i some_file_to_send can0:0x80 :0x90,0x12300\n" @@ -61,7 +66,7 @@ static const char help_msg[] = "\n" ; -static const char optstring[] = "?i:vs::rp:cnw::"; +static const char optstring[] = "?i:vs:rp:P:cnw::"; static void jcat_init_sockaddr_can(struct sockaddr_can *sac) @@ -72,16 +77,108 @@ static void jcat_init_sockaddr_can(struct sockaddr_can *sac) sac->can_addr.j1939.pgn = J1939_NO_PGN; } +static ssize_t jcat_send_one(struct jcat_priv *priv, int out_fd, + const void *buf, size_t buf_size) +{ + ssize_t num_sent; + int flags = 0; + + if (priv->polltimeout) + flags |= MSG_DONTWAIT; + + if (priv->valid_peername && !priv->todo_connect) + num_sent = sendto(out_fd, buf, buf_size, flags, + (struct sockaddr *)&priv->peername, + sizeof(priv->peername)); + else + num_sent = send(out_fd, buf, buf_size, flags); + + if (num_sent == -1) { + warn("%s: transfer error: %i", __func__, -errno); + return -errno; + } + + if (num_sent == 0) /* Should never happen */ { + warn("%s: transferred 0 bytes", __func__); + return -EINVAL; + } + + if (num_sent > buf_size) /* Should never happen */ { + warn("%s: send more then read", __func__); + return -EINVAL; + } + + return num_sent; +} + +static int jcat_poll(struct jcat_priv *priv) +{ + struct pollfd fds = { + .fd = priv->sock, + .events = POLLOUT, + }; + int ret; + + if (!priv->polltimeout) + return 0; + + ret = poll(&fds, 1, priv->polltimeout); + if (ret < 0) + return -errno; + else if (!ret) { + warn("%s: timeout", __func__); + return -ETIME; + } + + if (!(fds.revents & POLLOUT)) { + warn("%s: something else is wrong", __func__); + return -EIO; + } + + return 0; +} + +static int jcat_send_loop(struct jcat_priv *priv, int out_fd, char *buf, + size_t buf_size) +{ + ssize_t count, num_sent; + char *tmp_buf = buf; + int ret; + + count = buf_size; + + while (count) { + ret = jcat_poll(priv); + if (ret) { + if (ret == -EINTR) + continue; + else + return ret; + } + num_sent = jcat_send_one(priv, out_fd, tmp_buf, count); + if (num_sent < 0) + return num_sent; + + count -= num_sent; + tmp_buf += num_sent; + if (buf + buf_size < tmp_buf + count) { + warn("%s: send buffer is bigger than the read buffer", + __func__); + return -EINVAL; + } + } + return 0; +} + static int jcat_sendfile(struct jcat_priv *priv, int out_fd, int in_fd, off_t *offset, size_t count) { int ret = EXIT_SUCCESS; off_t orig = 0; char *buf; - size_t to_read, num_read, num_sent, tot_sent, buf_size; - int round = 0; + size_t to_read, num_read, buf_size; - buf_size = min((size_t)J1939_MAX_ETP_PACKET_SIZE, count); + buf_size = min(priv->max_transfer, count); buf = malloc(buf_size); if (!buf) { warn("can't allocate buf"); @@ -104,8 +201,6 @@ static int jcat_sendfile(struct jcat_priv *priv, int out_fd, int in_fd, } } - tot_sent = 0; - while (count > 0) { to_read = min(buf_size, count); @@ -117,35 +212,11 @@ static int jcat_sendfile(struct jcat_priv *priv, int out_fd, int in_fd, if (num_read == 0) break; /* EOF */ - if (priv->valid_peername && !priv->todo_connect) - num_sent = sendto(out_fd, buf, num_read, 0, - (void *)&priv->peername, - sizeof(priv->peername)); - else - num_sent = send(out_fd, buf, num_read, 0); - - if (num_sent == -1) { - warn("sendfile: write() transferr error"); - ret = EXIT_FAILURE; + ret = jcat_send_loop(priv, out_fd, buf, num_read); + if (ret) goto do_free; - } - if (num_sent == 0) /* Should never happen */ { - warn("sendfile: write() transferred 0 bytes"); - ret = EXIT_FAILURE; - goto do_free; - } - - if (num_sent != num_read) { - warn("sendfile: write() not full transfer: %zi %zi", - num_sent, num_read); - ret = EXIT_FAILURE; - goto do_free; - } - - round++; - count -= num_sent; - tot_sent += num_sent; + count -= num_read; } if (offset) { @@ -186,15 +257,16 @@ static size_t jcat_get_file_size(int fd) static int jcat_send(struct jcat_priv *priv) { + unsigned int size = 0; if (priv->todo_filesize) - priv->todo_send = jcat_get_file_size(priv->infile); + size = jcat_get_file_size(priv->infile); - if (!priv->todo_send) + if (!size) return EXIT_FAILURE; return jcat_sendfile(priv, priv->sock, priv->infile, NULL, - priv->todo_send); + size); } static int jcat_recv_one(struct jcat_priv *priv, uint8_t *buf, size_t buf_size) @@ -222,7 +294,7 @@ static int jcat_recv(struct jcat_priv *priv) size_t buf_size; uint8_t *buf; - buf_size = J1939_MAX_ETP_PACKET_SIZE; + buf_size = priv->max_transfer; buf = malloc(buf_size); if (!buf) { warn("can't allocate rx buf"); @@ -296,7 +368,10 @@ static int jcat_parse_args(struct jcat_priv *priv, int argc, char *argv[]) priv->todo_filesize = 1; break; case 's': - priv->todo_send = strtoul(optarg ?: "8", NULL, 0); + priv->max_transfer = strtoul(optarg, NULL, 0); + if (priv->max_transfer > J1939_MAX_ETP_PACKET_SIZE) + err(EXIT_FAILURE, "used value (%zu) is bigger then allowed maximal size: %u.\n", + priv->max_transfer, J1939_MAX_ETP_PACKET_SIZE); break; case 'r': priv->todo_recv = 1; @@ -304,6 +379,9 @@ static int jcat_parse_args(struct jcat_priv *priv, int argc, char *argv[]) case 'p': priv->todo_prio = strtoul(optarg, NULL, 0); break; + case 'P': + priv->polltimeout = strtoul(optarg, NULL, 0); + break; case 'c': priv->todo_connect = 1; break; @@ -343,6 +421,7 @@ int main(int argc, char *argv[]) priv->todo_prio = -1; priv->infile = STDIN_FILENO; priv->outfile = STDOUT_FILENO; + priv->max_transfer = J1939_MAX_ETP_PACKET_SIZE; jcat_init_sockaddr_can(&priv->sockname); jcat_init_sockaddr_can(&priv->peername);