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 diff --git a/jacd.c b/jacd.c index 0970520..a1a53d6 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), }; @@ -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)); @@ -241,13 +249,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; @@ -260,7 +276,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 +296,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 +585,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 +603,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/jcat.c b/jcat.c index 304a0dc..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,27 +257,25 @@ 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) { - 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; } @@ -225,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"); @@ -299,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; @@ -307,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; @@ -346,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); @@ -364,6 +440,8 @@ int main(int argc, char *argv[]) ret = jcat_send(priv); close(priv->infile); + close(priv->outfile); + close(priv->sock); return ret; } 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;