21 Commits
Author SHA1 Message Date
Oleksij RempelandGitHub 834ceef1f1 Isobus logformat updates (#636)
just some missing cleanups and fixing from the LLM session
2026-10-14 21:27:43 +02:00
Oliver Hartkopp f9086772a1 isobusfs: add printf format attribute to isobusfs_log()
All pr_*() log macros use isobusfs_log() which was declared without a
format attribute. Therefore the compiler did not check the format
strings against the provided arguments.

Add __attribute__((format(printf, 2, 3))) to let the compiler detect
mismatching format specifiers.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 19:25:06 +02:00
Oliver Hartkopp 8355b57133 isobusfs: fix printf format specifiers in log messages
Several log messages used format specifiers which did not match the
types of the provided arguments (e.g. %d or %i for size_t/ssize_t,
%ld for int64_t/time_t and size_t for the '.*' precision). On 64 bit
hosts (and for int64_t/time_t on 32 bit hosts) this leads to wrong
output or undefined behaviour when the log level is enabled.

Additionally the seek response position was compared to the requested
offset without le32toh() conversion which fails on big endian hosts.

Fix the format specifiers and add the missing le32toh() conversion.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 19:25:06 +02:00
Oleksij RempelandGitHub 0f55228325 Isobus and j1939acd fixes and improvements (#635)
The first three patches are from PR
https://github.com/linux-can/can-utils/pull/629 that was stuck due to
the review process. The review questions of commit
https://github.com/linux-can/can-utils/pull/629#pullrequestreview-4361812324
have been addressed in this PR (see commit message)

The most important fix that has an impact on the data structures on the
CAN bus is the last one ("isobusfs: pack the protocol structures").

"The isobusfs protocol structures describe the message layout defined in
ISO 11783-13 but were not packed. The compiler added padding bytes in
front of 16/32 bit values which follow an odd number of bytes, e.g. the
Read File Request (8 bytes according to C.3.5.2) had a size of 10 bytes
and the count value at the wrong position. Server and client of the
can-utils used the same structures and understood each other but the
messages were not compatible to other ISOBUS devices."

So this has to be checked and reviewed carefully as it breaks the former
protocol of can-utils (but likely fits the rest of the world).
2026-10-14 18:59:49 +02:00
Oliver Hartkopp aa54819b65 isobusfs: pack the protocol structures
The isobusfs protocol structures describe the message layout defined in
ISO 11783-13 but were not packed. The compiler added padding bytes in
front of 16/32 bit values which follow an odd number of bytes, e.g. the
Read File Request (8 bytes according to C.3.5.2) had a size of 10 bytes
and the count value at the wrong position. Server and client of the
can-utils used the same structures and understood each other but the
messages were not compatible to other ISOBUS devices. Additionally the
padding bytes sent uninitialized content.

Add __attribute__((__packed__)) to all protocol structures as it is
already done in j1939_vehicle_position.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oliver Hartkopp 8222f517b7 isobusfs: cli: use htole16() for the path name length in requests
The Change Current Directory and Open File requests assigned the path
name length to the little endian name_len element without conversion,
which leads to wrong values on big endian hosts.

Use htole16() as it is already done in the other requests.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oliver Hartkopp 775611dba2 isobusfs: srv: add missing break statements in current directory response
The switch statement which maps the errors of the current directory
access check to the ISOBUS FS error codes had no break statements. Due
to the fall through every error was reported as ISOBUSFS_ERR_OTHER.

Add the missing break statements.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oliver Hartkopp cd0ff30788 isobusfs: srv: check strdup() result when adding a new handle
The path of a handle is also used to mark the handle slot as used. When
strdup() failed the handle was returned to the client but the slot was
still marked as free and got reused (and the file descriptor of the
first user got lost) with the next open request.

Return -ENOMEM when the path can not be allocated. The callers close the
file descriptor and the handle slot remains unused.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oliver Hartkopp 3a980d83e0 isobusfs: srv: free handle path when closing the handle
The path of an opened file or directory handle is allocated with
strdup() but was not freed when the handle got closed. Every open/close
sequence leaked the path string.

Free the path before clearing the handle.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oliver Hartkopp 1a90b9a75d j1939acd: check length and address of Commanded Address messages
The Commanded Address message contains the 8 byte NAME and the new
source address. The received length was not checked, so the new source
address was taken from stale or uninitialized content of the receive
buffer for short messages. Also the idle and global addresses were
passed to claim_address() which terminates the daemon when bind() fails.

Check for the complete message length and only accept unicast addresses.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oliver Hartkopp 13dc8e9cc5 isobusfs: srv: check name length against the received message length
The Change Current Directory and Volume Status requests used the path
and volume name length from the request without checking it against
the received message length. Short messages with a big name length made
the server process stale content of the receive buffer as path or
volume name.

Check the name length against the message length, use le16toh() for the
CCD name length and fix the debug output of the volume name.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oliver Hartkopp d5571a5bc3 isobusfs: srv: pad short Read File responses within the allocated buffer
The Read File response buffer was allocated for the response header and
the requested data only. Short responses (e.g. count = 0) are extended to
ISOBUSFS_MIN_TRANSFER_LENGH which read beyond the allocated buffer and
sent heap content to the client.

Allocate at least ISOBUSFS_MIN_TRANSFER_LENGH bytes and fill the unused
bytes with 0xff.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oliver Hartkopp 33f7ddb5ed isobusfs: srv: check handle state and owner for read and seek requests
Read File and Seek File requests only checked the handle index to be
within the handles array. Unused or closed handle slots are zeroed
(fd = 0, dir = NULL), so a read request on such a handle read from the
server's stdin and sent the content to the client. Additionally every
client was able to read and seek handles opened by other clients.

Add isobusfs_srv_get_client_handle() which only returns handles that
are in use and have been opened by the requesting client.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:56 +00:00
Oleksij RempelandOliver Hartkopp c7a02c0258 isobusfs: fix directory read and seek semantics to match ISO 11783-13
Fix directory operations to comply with ISO 11783-13:2021 (sections
C.3.4.2 and C.3.5.2), which specifies that directory operations differ
significantly from standard file operations:
- The Count parameter in a Read File request represents the number of
  directory entries to read, not the number of bytes.
- The Offset parameter in a Seek File request represents the logical
  entry index, not a byte offset.

The previous implementation treated directories strictly as files,
using byte-based offsets and counts. This resulted in incorrect seeking
behavior and protocol violations when listing directories.

Align the implementation with the standard by:

1. Server side:
   - Introduce isobusfs_srv_dir_entry_visible() to consistently
     filter out invalid (unreadable, hidden, oversized) entries. This
     ensures that entry indices remain stable.
   - Implement isobusfs_srv_dir_skip_entries() to advance the
     directory stream by logical visible entries rather than bytes.
   - Update the Read File handler to interpret count as the
     maximum number of entries and return the number of entries read
     in the response header.
   - Update the Seek File handler to seek by entry index.

2. Client side:
   - Calculate the request count based on the number of minimal-size
     entries that fit into the maximum data length.
   - Interpret the response count as the number of entries received
     rather than the byte length of the payload.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2026-10-14 10:21:56 +00:00
Oleksij RempelandOliver Hartkopp a63fd488b2 isobusfs: treat interactive exit as control flow, not error
The cmd_exit() function used -EINTR to signal a clean exit from the
interactive mode. This is semantically incorrect because EINTR is an
errno value meant for system call interruptions, not application-level
control flow.

Stop using -EINTR for cmd_exit(). Introduce ISOBUSFS_CLI_RET_EXIT (a
positive return code) to distinguish control flow from actual errors.
Map this to exit code 0 in main(), keeping negative errno values for
real errors. This makes the exit path explicit and prevents confusion
with actual interrupted system calls.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2026-10-14 10:21:55 +00:00
Oleksij RempelandOliver Hartkopp 64280dc9c3 isobusfs: selftest: Handle read requests larger than file size
Add expected_size field to test patterns to properly validate cases
where the requested read size exceeds the actual file size. This allows
testing the server's behavior when clients request more data than is
available.

When a read request is larger than the file, the server correctly
returns data up to EOF. The test framework now distinguishes between
this expected scenario and genuine read failures.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
[socketcan: addressed review comments from PR #629:
 - keep uint32_t instead of size_t for offset/read_size/expected_size:
   ISO 11783-13 limits the file offset (Seek File) and the file size
   (directory entry) to 32 bit, so uint32_t matches the protocol. The
   sum offset + read_size can exceed 32 bit (see UINT32_MAX pattern)
   and is therefore calculated in int64_t. size_t would not help here
   as it is only 32 bit wide on 32 bit targets.
 - remaining_size is a signed int64_t: the signed type is needed to
   detect the 'remaining_size < 0' case (server returned more data than
   requested) and int64_t holds the 33 bit sum on all platforms.
 - fix printf format for the uint32_t read_offset (%zu -> %u)]
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 10:21:55 +00:00
Oliver Hartkopp 1663fc32b3 slcanpty: use the SLCAN message length when parsing commands
pty2can() detected complete SLCAN messages by looking for the '\r'
termination but did not use this message length for parsing. The
content was read at fixed positions and the start of the following
message was derived from the parsed content.

Too short messages (e.g. 'T1\r') read the DLC and data from stale
buffer content and sent a phantom CAN frame. Following commands got
lost after short messages, unknown commands or frames with timestamp.

Terminate the current message at its '\r' position, check that the
CAN ID fits into the message and always continue with the next message
behind the '\r'.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 11:15:54 +02:00
Oliver Hartkopp 38cf8dd1a5 cangw: fix NULL pointer dereference in modification parsing
parse_mod() and parse_fdmod() did not check the return value of
strchr() when looking for the ':' delimiters. A modification definition
without ':' (e.g. '-m AND') led to a segmentation fault.

Add the missing NULL pointer checks.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 11:15:54 +02:00
Oliver Hartkopp 411a68675f lib: snprintf_can_error_frame: document and check required buffer size
The helper functions for the error frame content added the return
values of snprintf() to the buffer offset without checking for
truncation. With a too small buffer the following 'len - n' calculation
wrapped around (size_t) and subsequent snprintf() calls could write
beyond the end of the buffer.

As the maximum output length is known, introduce CANERR_BUFFSZ in lib.h
with a description how the required buffer size is calculated and
return an empty string if the provided buffer is smaller. The only user
candump provides a buffer of more than 6000 bytes for this function.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 11:15:54 +02:00
Oliver Hartkopp 6bdb574707 asc2log: use unsigned types for DLC and data length values
The DLC and data length values were read into signed integers with
%x and %d. Negative values (e.g. '-1' or 'ffffffff') passed the range
checks and led to len values of 255 or 65535. Via the union cfu
these classic CAN frames were then printed as CAN XL frames.

Use unsigned int for dlc/dlen and %u for the data length so that
negative values are caught by the existing range checks.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 11:15:54 +02:00
Oliver Hartkopp fa647cc3e2 asc2log: do not read beyond the end of line when parsing hex data
The data parsing loops in the CANFD/CANXL evaluation functions jumped
three characters forward after each hex byte without checking the
separator. When a line ended directly after a hex byte (e.g. last line
without newline or a line split by fgets()) the pointer skipped the
string termination and continued parsing stale content from previous
lines - or in the worst case read beyond the input buffer.

Factor out the four identical loops into get_hex_data() which requires
a whitespace separator behind each hex byte.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2026-10-14 11:15:54 +02:00
24 changed files with 560 additions and 265 deletions
+64 -81
View File
@@ -42,6 +42,7 @@
* *
*/ */
#include <ctype.h>
#include <libgen.h> #include <libgen.h>
#include <locale.h> #include <locale.h>
#include <stdio.h> #include <stdio.h>
@@ -114,6 +115,42 @@ static void get_can_id(canid_t *can_id, char *idstring, int base)
*can_id |= strtoul(idstring, NULL, base); *can_id |= strtoul(idstring, NULL, base);
} }
/*
* Read 'len' ASCII hex bytes separated by single whitespace characters.
* Returns a pointer to the content behind the data or NULL on error.
*/
static char *get_hex_data(char *ptr, unsigned char *data, int len)
{
unsigned char ctmp;
int i;
for (i = 0; i < len; i++) {
ctmp = asc2nibble(ptr[0]);
if (ctmp > 0x0F)
return NULL;
data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return NULL;
data[i] |= ctmp;
/*
* The hex byte has to be followed by a separator (space/tab)
* or an EOL char ('\n', '\r'). This also ensures that we do
* not skip the string termination with ptr += 3 below.
*/
if (!isspace((unsigned char)ptr[2]))
return NULL;
ptr += 3; /* start of next ASCII hex byte */
}
return ptr;
}
static void calc_tv(struct timeval *tv, struct timeval *read_tv, static void calc_tv(struct timeval *tv, struct timeval *read_tv,
struct timeval *date_tv, char timestamps, int dplace) struct timeval *date_tv, char timestamps, int dplace)
{ {
@@ -155,7 +192,7 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
struct canfd_frame cf = { 0 }; struct canfd_frame cf = { 0 };
struct can_frame *ccf = (struct can_frame *)&cf; /* for len8_dlc */ struct can_frame *ccf = (struct can_frame *)&cf; /* for len8_dlc */
char rtr; char rtr;
int dlc = 0; unsigned int dlc = 0;
int len = 0; int len = 0;
int data[8]; int data[8];
char idstr[21]; char idstr[21];
@@ -261,13 +298,12 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
static struct timeval tv; /* current frame timestamp */ static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */ static struct timeval read_tv; /* frame timestamp from ASC file */
struct canfd_frame cf = { 0 }; struct canfd_frame cf = { 0 };
unsigned char brs, esi, ctmp; unsigned char brs, esi;
unsigned int flags; unsigned int flags;
int dlc, dlen = 0; unsigned int dlc, dlen = 0;
char idstr[21]; char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */ char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr; char *ptr;
int i;
int n = 0; /* sscanf consumed characters */ int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec; unsigned long long sec, usec;
@@ -283,12 +319,12 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
*/ */
/* check for valid line without symbolic name */ /* check for valid line without symbolic name */
if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %hhx %hhx %x %d %n", if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %hhx %hhx %x %u %n",
&sec, &usec, &interface, &sec, &usec, &interface,
dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) { dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) {
/* check for valid line with a symbolic name */ /* check for valid line with a symbolic name */
if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %*s %hhx %hhx %x %d %n", if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %*s %hhx %hhx %x %u %n",
&sec, &usec, &interface, &sec, &usec, &interface,
dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) { dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) {
@@ -328,21 +364,9 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
cf.len = dlen; cf.len = dlen;
for (i = 0; i < dlen; i++) { ptr = get_hex_data(ptr, cf.data, dlen);
ctmp = asc2nibble(ptr[0]); if (!ptr)
if (ctmp > 0x0F) return;
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip MessageDuration and MessageLength to get Flags value */ /* skip MessageDuration and MessageLength to get Flags value */
if (sscanf(ptr, " %*x %*x %x ", &flags) != 1) if (sscanf(ptr, " %*x %*x %x ", &flags) != 1)
@@ -387,13 +411,11 @@ static void eval_canxl_cc(char* buf, struct timeval *date_tvp, char timestamps,
static struct timeval tv; /* current frame timestamp */ static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */ static struct timeval read_tv; /* frame timestamp from ASC file */
struct can_frame cf = { 0 }; struct can_frame cf = { 0 };
unsigned char ctmp;
unsigned int flags; unsigned int flags;
int dlc, dlen = 0; unsigned int dlc, dlen = 0;
char idstr[21]; char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */ char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr; char *ptr;
int i;
int n = 0; /* sscanf consumed characters */ int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec; unsigned long long sec, usec;
@@ -408,7 +430,7 @@ static void eval_canxl_cc(char* buf, struct timeval *date_tvp, char timestamps,
if (sscanf(buf, if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */ "%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */ "%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%x %d %n", /* DLC, Datalen */ "%x %u %n", /* DLC, Datalen */
&sec, &usec, &interface, dir, &sec, &usec, &interface, dir,
idstr, idstr,
&dlc, &dlen, &n) != 7) { &dlc, &dlen, &n) != 7) {
@@ -416,7 +438,7 @@ static void eval_canxl_cc(char* buf, struct timeval *date_tvp, char timestamps,
if (sscanf(buf, if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */ "%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */ "%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %x %d %n", /* sym name, DLC, Datalen */ "%*s %x %u %n", /* sym name, DLC, Datalen */
&sec, &usec, &interface, dir, &sec, &usec, &interface, dir,
idstr, idstr,
&dlc, &dlen, &n) != 7) { &dlc, &dlen, &n) != 7) {
@@ -452,21 +474,9 @@ static void eval_canxl_cc(char* buf, struct timeval *date_tvp, char timestamps,
cf.len = dlen; cf.len = dlen;
for (i = 0; i < dlen; i++) { ptr = get_hex_data(ptr, cf.data, dlen);
ctmp = asc2nibble(ptr[0]); if (!ptr)
if (ctmp > 0x0F) return;
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip FCRC to get Flags value */ /* skip FCRC to get Flags value */
if (sscanf(ptr, "%*x %x ", &flags) != 1) if (sscanf(ptr, "%*x %x ", &flags) != 1)
@@ -498,13 +508,11 @@ static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps,
static struct timeval tv; /* current frame timestamp */ static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */ static struct timeval read_tv; /* frame timestamp from ASC file */
struct canfd_frame cf = { 0 }; struct canfd_frame cf = { 0 };
unsigned char ctmp;
unsigned int flags; unsigned int flags;
int dlc, dlen = 0; unsigned int dlc, dlen = 0;
char idstr[21]; char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */ char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr; char *ptr;
int i;
int n = 0; /* sscanf consumed characters */ int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec; unsigned long long sec, usec;
@@ -519,7 +527,7 @@ static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps,
if (sscanf(buf, if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */ "%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */ "%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%x %d %n", /* DLC, Datalen */ "%x %u %n", /* DLC, Datalen */
&sec, &usec, &interface, dir, &sec, &usec, &interface, dir,
idstr, idstr,
&dlc, &dlen, &n) != 7) { &dlc, &dlen, &n) != 7) {
@@ -527,7 +535,7 @@ static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps,
if (sscanf(buf, if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */ "%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */ "%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %x %d %n", /* sym name, DLC, Datalen */ "%*s %x %u %n", /* sym name, DLC, Datalen */
&sec, &usec, &interface, dir, &sec, &usec, &interface, dir,
idstr, idstr,
&dlc, &dlen, &n) != 7) { &dlc, &dlen, &n) != 7) {
@@ -563,21 +571,9 @@ static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps,
cf.len = dlen; cf.len = dlen;
for (i = 0; i < dlen; i++) { ptr = get_hex_data(ptr, cf.data, dlen);
ctmp = asc2nibble(ptr[0]); if (!ptr)
if (ctmp > 0x0F) return;
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip stuff field and FCRC to get Flags value */ /* skip stuff field and FCRC to get Flags value */
if (sscanf(ptr, "%*s %*s %x ", &flags) != 1) if (sscanf(ptr, "%*s %*s %x ", &flags) != 1)
@@ -605,13 +601,12 @@ static void eval_canxl_xl(char* buf, struct timeval *date_tvp, char timestamps,
static struct timeval tv; /* current frame timestamp */ static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */ static struct timeval read_tv; /* frame timestamp from ASC file */
struct canxl_frame cf = { 0 }; struct canxl_frame cf = { 0 };
unsigned char sdt, vcid, secbit, ctmp; unsigned char sdt, vcid, secbit;
unsigned int af, flags; unsigned int af, flags;
int dlc, dlen = 0; unsigned int dlc, dlen = 0;
char idstr[21]; char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */ char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr; char *ptr;
int i;
int n = 0; /* sscanf consumed characters */ int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec; unsigned long long sec, usec;
@@ -627,7 +622,7 @@ static void eval_canxl_xl(char* buf, struct timeval *date_tvp, char timestamps,
if (sscanf(buf, if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */ "%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */ "%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%hhx %hhx %x %d " /* SDT, SEC, DLC, Datalen */ "%hhx %hhx %x %u " /* SDT, SEC, DLC, Datalen */
"%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */ "%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */
&sec, &usec, &interface, dir, &sec, &usec, &interface, dir,
idstr, idstr,
@@ -637,7 +632,7 @@ static void eval_canxl_xl(char* buf, struct timeval *date_tvp, char timestamps,
if (sscanf(buf, if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */ "%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */ "%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %hhx %hhx %x %d " /* sym name, SDT, SEC, DLC, Datalen */ "%*s %hhx %hhx %x %u " /* sym name, SDT, SEC, DLC, Datalen */
"%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */ "%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */
&sec, &usec, &interface, dir, &sec, &usec, &interface, dir,
idstr, idstr,
@@ -689,21 +684,9 @@ static void eval_canxl_xl(char* buf, struct timeval *date_tvp, char timestamps,
cf.len = dlen; cf.len = dlen;
for (i = 0; i < dlen; i++) { ptr = get_hex_data(ptr, cf.data, dlen);
ctmp = asc2nibble(ptr[0]); if (!ptr)
if (ctmp > 0x0F) return;
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip FCRC to get Flags value */ /* skip FCRC to get Flags value */
if (sscanf(ptr, "%*x %x ", &flags) != 1) if (sscanf(ptr, "%*x %x ", &flags) != 1)
+4 -4
View File
@@ -338,7 +338,7 @@ static int parse_mod(char *optarg, struct modattr *modmsg)
ptr = optarg; ptr = optarg;
nptr = strchr(ptr, ':'); nptr = strchr(ptr, ':');
if ((nptr - ptr > 3) || (nptr - ptr == 0)) if (!nptr || (nptr - ptr > 3) || (nptr - ptr == 0))
return 1; return 1;
if (!strncmp(ptr, "AND", 3)) if (!strncmp(ptr, "AND", 3))
@@ -355,7 +355,7 @@ static int parse_mod(char *optarg, struct modattr *modmsg)
ptr = nptr+1; ptr = nptr+1;
nptr = strchr(ptr, ':'); nptr = strchr(ptr, ':');
if ((nptr - ptr > 3) || (nptr - ptr == 0)) if (!nptr || (nptr - ptr > 3) || (nptr - ptr == 0))
return 3; return 3;
modmsg->modtype = 0; modmsg->modtype = 0;
@@ -406,7 +406,7 @@ static int parse_fdmod(char *optarg, struct fdmodattr *modmsg)
ptr = optarg; ptr = optarg;
nptr = strchr(ptr, ':'); nptr = strchr(ptr, ':');
if ((nptr - ptr > 3) || (nptr - ptr == 0)) if (!nptr || (nptr - ptr > 3) || (nptr - ptr == 0))
return 1; return 1;
if (!strncmp(ptr, "AND", 3)) if (!strncmp(ptr, "AND", 3))
@@ -423,7 +423,7 @@ static int parse_fdmod(char *optarg, struct fdmodattr *modmsg)
ptr = nptr+1; ptr = nptr+1;
nptr = strchr(ptr, ':'); nptr = strchr(ptr, ':');
if ((nptr - ptr > 4) || (nptr - ptr == 0)) if (!nptr || (nptr - ptr > 4) || (nptr - ptr == 0))
return 3; return 3;
modmsg->modtype = 0; modmsg->modtype = 0;
+4
View File
@@ -671,6 +671,10 @@ int main(int argc, char *argv[])
while (1) { while (1) {
ret = isobusfs_cli_process_events_and_tasks(priv); ret = isobusfs_cli_process_events_and_tasks(priv);
if (ret == ISOBUSFS_CLI_RET_EXIT) {
ret = 0;
break;
}
if (ret) if (ret)
break; break;
} }
+3
View File
@@ -13,6 +13,9 @@
#define ISOBUSFS_CLI_MAX_EPOLL_EVENTS 10 #define ISOBUSFS_CLI_MAX_EPOLL_EVENTS 10
#define ISOBUSFS_CLI_DEFAULT_WAIT_TIMEOUT_MS 1000 /* ms */ #define ISOBUSFS_CLI_DEFAULT_WAIT_TIMEOUT_MS 1000 /* ms */
/* internal return codes, not errno values */
#define ISOBUSFS_CLI_RET_EXIT 1
enum isobusfs_cli_state { enum isobusfs_cli_state {
ISOBUSFS_CLI_STATE_CONNECTING, ISOBUSFS_CLI_STATE_CONNECTING,
ISOBUSFS_CLI_STATE_IDLE, ISOBUSFS_CLI_STATE_IDLE,
+4 -3
View File
@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2023 Oleksij Rempel <linux@rempel-privat.de> // SPDX-FileCopyrightText: 2023 Oleksij Rempel <linux@rempel-privat.de>
#include <errno.h> #include <errno.h>
#include <inttypes.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@@ -95,7 +96,7 @@ int isobusfs_cli_ccm_send(struct isobusfs_priv *priv)
} }
if (time_diff < -ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) { if (time_diff < -ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) {
pr_warn("too late to send next fs status message: %ld ms", pr_warn("too late to send next fs status message: %" PRId64 " ms",
time_diff); time_diff);
} }
@@ -152,7 +153,7 @@ static int isobusfs_cli_rx_fs_status(struct isobusfs_priv *priv,
int ret = 0; int ret = 0;
if (msg->len != sizeof(*fs_status)) { if (msg->len != sizeof(*fs_status)) {
pr_warn("wrong message length: %d", msg->len); pr_warn("wrong message length: %zd", msg->len);
return -EINVAL; return -EINVAL;
} }
@@ -178,7 +179,7 @@ static int isobusfs_cli_rx_fs_property_res(struct isobusfs_priv *priv,
} }
if (msg->len != sizeof(*fs_prop)) { if (msg->len != sizeof(*fs_prop)) {
pr_warn("wrong message length: %d", msg->len); pr_warn("wrong message length: %zd", msg->len);
return -EINVAL; return -EINVAL;
} }
+2 -2
View File
@@ -21,7 +21,7 @@ int isobusfs_cli_ccd_req(struct isobusfs_priv *priv, const char *name,
int ret; int ret;
if (name_len > ISOBUSFS_MAX_PATH_NAME_LENGTH) { if (name_len > ISOBUSFS_MAX_PATH_NAME_LENGTH) {
pr_warn("path name too long: %i, max is %i", name_len, pr_warn("path name too long: %zu, max is %i", name_len,
ISOBUSFS_MAX_PATH_NAME_LENGTH); ISOBUSFS_MAX_PATH_NAME_LENGTH);
return -EINVAL; return -EINVAL;
} }
@@ -43,7 +43,7 @@ int isobusfs_cli_ccd_req(struct isobusfs_priv *priv, const char *name,
req->tan = isobusfs_cli_get_next_tan(priv); req->tan = isobusfs_cli_get_next_tan(priv);
memcpy(&req->name[0], name, name_len); memcpy(&req->name[0], name, name_len);
req->name_len = name_len; req->name_len = htole16(name_len);
if (padding_size) { if (padding_size) {
/* Fill the rest of the res structure with 0xff */ /* Fill the rest of the res structure with 0xff */
+2 -2
View File
@@ -286,7 +286,7 @@ int isobusfs_cli_fa_of_req(struct isobusfs_priv *priv, const char *name,
int ret; int ret;
if (name_len > ISOBUSFS_MAX_PATH_NAME_LENGTH) { if (name_len > ISOBUSFS_MAX_PATH_NAME_LENGTH) {
pr_warn("path name too long: %i, max is %i", name_len, pr_warn("path name too long: %zu, max is %i", name_len,
ISOBUSFS_MAX_PATH_NAME_LENGTH); ISOBUSFS_MAX_PATH_NAME_LENGTH);
return -EINVAL; return -EINVAL;
} }
@@ -308,7 +308,7 @@ int isobusfs_cli_fa_of_req(struct isobusfs_priv *priv, const char *name,
req->tan = isobusfs_cli_get_next_tan(priv); req->tan = isobusfs_cli_get_next_tan(priv);
req->flags = flags; req->flags = flags;
memcpy(&req->name[0], name, name_len); memcpy(&req->name[0], name, name_len);
req->name_len = name_len; req->name_len = htole16(name_len);
if (padding_size) { if (padding_size) {
/* Fill the rest of the res structure with 0xff */ /* Fill the rest of the res structure with 0xff */
+81 -34
View File
@@ -16,6 +16,12 @@
#define MAX_COMMAND_LENGTH 256 #define MAX_COMMAND_LENGTH 256
#define MAX_DISPLAY_FILENAME_LENGTH 100 #define MAX_DISPLAY_FILENAME_LENGTH 100
/*
* ISO 11783-13:2021 B.21 minimal directory entry payload size in bytes:
* 1 (name length) + 1 (min name byte) + 1 (attributes) +
* 2 (date) + 2 (time) + 4 (size).
*/
#define ISOBUSFS_MIN_DIR_ENTRY_SIZE (1 + 1 + 1 + 2 + 2 + 4)
struct command_mapping { struct command_mapping {
const char *command; const char *command;
@@ -66,8 +72,8 @@ static int cmd_help(struct isobusfs_priv *priv, const char *options)
static int cmd_exit(struct isobusfs_priv *priv, const char *options) static int cmd_exit(struct isobusfs_priv *priv, const char *options)
{ {
pr_int("exit interactive mode\n"); pr_int("exit interactive mode\n");
/* Return -EINTR to indicate the program should exit */
return -EINTR; return ISOBUSFS_CLI_RET_EXIT;
} }
static int cmd_dmesg(struct isobusfs_priv *priv, const char *options) static int cmd_dmesg(struct isobusfs_priv *priv, const char *options)
@@ -510,8 +516,12 @@ isobusfs_cli_ls_handle_open_dir_sent(struct isobusfs_priv *priv,
ctx->handle = res->handle; ctx->handle = res->handle;
ctx->offset = 0;
ctx->entry_count = 0;
ret = isobusfs_cli_send_and_register_fa_sf_event(priv, ctx->handle, ret = isobusfs_cli_send_and_register_fa_sf_event(priv, ctx->handle,
0, ctx->entry_count, ISOBUSFS_FA_SEEK_SET,
ctx->offset,
cb, ctx); cb, ctx);
if (ret) if (ret)
pr_int("Failed to send seek file request: %i\n", ret); pr_int("Failed to send seek file request: %i\n", ret);
@@ -530,21 +540,23 @@ isobusfs_cli_ls_handle_seek_dir_sent(struct isobusfs_priv *priv,
{ {
isobusfs_event_callback cb = isobusfs_cli_ls_event_callback; isobusfs_event_callback cb = isobusfs_cli_ls_event_callback;
struct isobusfs_fa_seekf_res *res = struct isobusfs_fa_seekf_res *res =
(struct isobusfs_fa_seekf_res *)msg; (struct isobusfs_fa_seekf_res *)msg->buf;
uint16_t count; uint16_t count;
int ret; int ret;
if (isobusfs_cli_int_is_error(priv, 0, res->error_code, res->tan)) if (isobusfs_cli_int_is_error(priv, 0, res->error_code, res->tan))
goto error; goto error;
if (res->position != ctx->offset) { if (le32toh(res->position) != ctx->offset) {
pr_int("Failed to seek to position %zu, got %zu\n", pr_int("Failed to seek to position %zu, got %u\n",
ctx->offset, res->position); ctx->offset, le32toh(res->position));
goto error; goto error;
} }
/* set max possible number fitting in to 16bits */ /* ISO 11783-13:2021 C.3.5.2: count is number of directory entries. */
count = UINT16_MAX; count = ISOBUSFS_MAX_DATA_LENGH / ISOBUSFS_MIN_DIR_ENTRY_SIZE;
if (!count)
count = 1;
ctx->request_count = count; ctx->request_count = count;
ret = isobusfs_cli_send_and_register_fa_rf_event(priv, ctx->handle, ret = isobusfs_cli_send_and_register_fa_rf_event(priv, ctx->handle,
@@ -616,8 +628,8 @@ static bool isobusfs_cli_extract_directory_entry(const uint8_t *buffer,
uint16_t *file_time, uint16_t *file_time,
uint32_t *file_size) uint32_t *file_size)
{ {
size_t entry_total_len, copy_len;
uint8_t filename_length; uint8_t filename_length;
size_t entry_total_len;
if (*pos + 2 > buffer_length) { if (*pos + 2 > buffer_length) {
pr_int("Error: Incomplete data in buffer\n"); pr_int("Error: Incomplete data in buffer\n");
@@ -633,8 +645,14 @@ static bool isobusfs_cli_extract_directory_entry(const uint8_t *buffer,
} }
(*pos)++; (*pos)++;
strncpy(filename, (const char *)buffer + *pos, filename_length);
filename[filename_length] = '\0'; if (filename_length > ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH)
copy_len = ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH;
else
copy_len = filename_length;
strncpy(filename, (const char *)buffer + *pos, copy_len);
filename[copy_len] = '\0';
*pos += filename_length; *pos += filename_length;
if (filename_length > MAX_DISPLAY_FILENAME_LENGTH) { if (filename_length > MAX_DISPLAY_FILENAME_LENGTH) {
/* Truncate the filename and replace the last character /* Truncate the filename and replace the last character
@@ -688,15 +706,17 @@ isobusfs_cli_print_directory_entry(struct isobusfs_cli_ls_context *ctx,
static void static void
isobusfs_cli_print_directory_entries(struct isobusfs_cli_ls_context *ctx, isobusfs_cli_print_directory_entries(struct isobusfs_cli_ls_context *ctx,
const uint8_t *buffer, const uint8_t *buffer,
size_t buffer_length) size_t buffer_length,
uint16_t max_entries)
{ {
char filename[ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH + 1]; char filename[ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH + 1];
uint16_t file_date, file_time; uint16_t file_date, file_time;
uint32_t file_size; uint32_t file_size;
uint8_t attributes; uint8_t attributes;
size_t pos = 0; size_t pos = 0;
uint16_t entries = 0;
while (pos < buffer_length) { while (pos < buffer_length && entries < max_entries) {
if (!isobusfs_cli_extract_directory_entry(buffer, buffer_length, if (!isobusfs_cli_extract_directory_entry(buffer, buffer_length,
&pos, filename, &pos, filename,
&attributes, &attributes,
@@ -709,6 +729,7 @@ isobusfs_cli_print_directory_entries(struct isobusfs_cli_ls_context *ctx,
file_date, file_time, file_date, file_time,
file_size); file_size);
ctx->entry_count++; ctx->entry_count++;
entries++;
} }
} }
@@ -721,26 +742,42 @@ isobusfs_cli_ls_handle_read_dir_sent(struct isobusfs_priv *priv,
(struct isobusfs_read_file_response *)msg->buf; (struct isobusfs_read_file_response *)msg->buf;
size_t buffer_length = msg->len - sizeof(*res); size_t buffer_length = msg->len - sizeof(*res);
isobusfs_event_callback cb; isobusfs_event_callback cb;
size_t entries_before;
size_t entries_in_message;
uint16_t count; uint16_t count;
int ret; int ret;
pr_debug("< rx: Read File Response. Error code: %i", res->error_code); pr_debug("< rx: Read File Response. Error code: %i", res->error_code);
if (isobusfs_cli_int_is_error(priv, 0, res->error_code, res->tan)) if (isobusfs_cli_int_is_error(priv, 0, res->error_code, res->tan))
goto error; goto error;
count = le16toh(res->count); count = le16toh(res->count);
if (count && count != buffer_length) { if (count && buffer_length) {
pr_int("Buffer length mismatch: %u != %zu\n", count, entries_before = ctx->entry_count;
buffer_length); isobusfs_cli_print_directory_entries(ctx, res->data,
goto error; buffer_length, count);
entries_in_message = ctx->entry_count - entries_before;
} else {
entries_in_message = 0;
} }
if (count) if (count != entries_in_message) {
isobusfs_cli_print_directory_entries(ctx, res->data, pr_warn("Directory entry count mismatch: server sent %u, parsed %zu\n",
buffer_length); count, entries_in_message);
/* Continue processing if we parsed at least some entries.
* Strict validation would reject valid responses if parsing
* fails partway through due to corruption.
*/
if (entries_in_message == 0 && count > 0) {
pr_int("Error: Failed to parse any directory entries\n");
goto error;
}
}
cb = isobusfs_cli_ls_event_callback; cb = isobusfs_cli_ls_event_callback;
if (count) {
if (res->error_code == ISOBUSFS_ERR_END_OF_FILE) {
ret = isobusfs_cli_send_and_register_fa_cf_event(priv, ret = isobusfs_cli_send_and_register_fa_cf_event(priv,
ctx->handle, ctx->handle,
cb, ctx); cb, ctx);
@@ -750,21 +787,31 @@ isobusfs_cli_ls_handle_read_dir_sent(struct isobusfs_priv *priv,
} }
ctx->state = ISOBUSFS_CLI_LS_STATE_CLOSE_DIR_SENT; ctx->state = ISOBUSFS_CLI_LS_STATE_CLOSE_DIR_SENT;
} else { return;
ctx->offset = ctx->entry_count;
ret = isobusfs_cli_send_and_register_fa_sf_event(priv,
ctx->handle, 0,
ctx->offset,
cb, ctx);
if (ret)
pr_int("Failed to send seek file request: %i\n", ret);
ctx->state = ISOBUSFS_CLI_LS_STATE_SEEK_DIR_SENT;
} }
if (!count) {
pr_int("Error: zero-length read without EOF\n");
goto error;
}
/*
* Directory seek offset is entry index, not byte offset.
* Server side seek rewinds and skips "offset" entries.
*/
ctx->offset = ctx->entry_count;
ret = isobusfs_cli_send_and_register_fa_sf_event(priv,
ctx->handle, 0,
ctx->offset,
cb, ctx);
if (ret)
pr_int("Failed to send seek file request: %i\n", ret);
ctx->state = ISOBUSFS_CLI_LS_STATE_SEEK_DIR_SENT;
return; return;
error: error:
ctx->state = ISOBUSFS_CLI_LS_STATE_ERROR; ctx->state = ISOBUSFS_CLI_LS_STATE_ERROR;
} }
@@ -821,7 +868,7 @@ static void isobusfs_cli_process_ls_command(struct isobusfs_priv *priv,
ctx->handle, NULL, NULL); ctx->handle, NULL, NULL);
} }
pr_int("Entries found: %i\n", ctx->entry_count); pr_int("Entries found: %zu\n", ctx->entry_count);
priv->int_busy = false; priv->int_busy = false;
isobusfs_cli_ls_free_ctx(ctx); isobusfs_cli_ls_free_ctx(ctx);
isobusfs_cli_promt(priv); isobusfs_cli_promt(priv);
+40 -22
View File
@@ -603,23 +603,24 @@ struct isobusfs_cli_test_rf_path {
uint8_t flags; uint8_t flags;
uint32_t offset; uint32_t offset;
uint32_t read_size; uint32_t read_size;
uint32_t expected_size;
bool expect_pass; bool expect_pass;
}; };
static struct isobusfs_cli_test_rf_path test_rf_patterns[] = { static struct isobusfs_cli_test_rf_path test_rf_patterns[] = {
/* expected result \\vol1\dir1\dir2\ */ /* expected result \\vol1\dir1\dir2\ */
{ "\\\\vol1\\dir1\\dir2\\file1k", 0, 0, 0, true }, { "\\\\vol1\\dir1\\dir2\\file1k", 0, 0, 0, 0, true },
{ "\\\\vol1\\dir1\\dir2\\file1k", 0, 0, 1, true }, { "\\\\vol1\\dir1\\dir2\\file1k", 0, 0, 1, 1, true },
{ "\\\\vol1\\dir1\\dir2\\file1k", 0, 1, 1, true }, { "\\\\vol1\\dir1\\dir2\\file1k", 0, 1, 1, 1, true },
{ "\\\\vol1\\dir1\\dir2\\file1k", 0, 2, 1, true }, { "\\\\vol1\\dir1\\dir2\\file1k", 0, 2, 1, 1, true },
{ "\\\\vol1\\dir1\\dir2\\file1k", 0, 3, 1, true }, { "\\\\vol1\\dir1\\dir2\\file1k", 0, 3, 1, 1, true },
{ "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, 8, true }, { "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, 8, 8, true },
{ "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, 8 * 100, true }, { "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, 8 * 100, 8 * 100, true },
{ "\\\\vol1\\dir1\\dir2\\file1m", 0, 100, 8 * 100, true }, { "\\\\vol1\\dir1\\dir2\\file1m", 0, 100, 8 * 100, 8 * 100, true },
{ "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, ISOBUSFS_MAX_DATA_LENGH, true }, { "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, ISOBUSFS_MAX_DATA_LENGH, ISOBUSFS_MAX_DATA_LENGH, true },
{ "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, (ISOBUSFS_MAX_DATA_LENGH & ~3) + 16, true }, { "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, (ISOBUSFS_MAX_DATA_LENGH & ~3) + 16, (ISOBUSFS_MAX_DATA_LENGH & ~3) + 16, true },
{ "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, ISOBUSFS_MAX_DATA_LENGH + 1, true }, { "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, ISOBUSFS_MAX_DATA_LENGH + 1, ISOBUSFS_MAX_DATA_LENGH + 1, true },
{ "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, -1, true }, { "\\\\vol1\\dir1\\dir2\\file1m", 0, 0, UINT32_MAX, 1024 * 1024, true },
}; };
size_t current_rf_pattern_test; size_t current_rf_pattern_test;
@@ -678,7 +679,8 @@ static int isobusfs_cli_test_rf_req(struct isobusfs_priv *priv, bool *complete)
&test_rf_patterns[current_rf_pattern_test]; &test_rf_patterns[current_rf_pattern_test];
uint32_t actual_sum, expected_sum; uint32_t actual_sum, expected_sum;
struct timespec current_time; struct timespec current_time;
ssize_t remaining_size, read_size; int64_t remaining_size;
ssize_t read_size;
int ret; int ret;
clock_gettime(CLOCK_MONOTONIC, &current_time); clock_gettime(CLOCK_MONOTONIC, &current_time);
@@ -801,16 +803,23 @@ static int isobusfs_cli_test_rf_req(struct isobusfs_priv *priv, bool *complete)
free(priv->read_data); free(priv->read_data);
priv->read_data = NULL; priv->read_data = NULL;
remaining_size = (tp->offset + tp->read_size) - remaining_size = ((int64_t)tp->offset + tp->read_size) -
(priv->read_offset + priv->read_data_len); ((int64_t)priv->read_offset + priv->read_data_len);
pr_debug("remaining_size: %zd, read_offset: %zu, read_data_len: %zu, test read size: %zu, test offset %zu", pr_debug("remaining_size: %lld, read_offset: %u, read_data_len: %zu, test read size: %u, test offset %u",
remaining_size, priv->read_offset, priv->read_data_len, (long long)remaining_size, priv->read_offset, priv->read_data_len,
tp->read_size, tp->offset); tp->read_size, tp->offset);
if (remaining_size < 0) { if (remaining_size < 0) {
pr_err("pattern test failed: %s. Read size is too big", pr_err("pattern test failed: %s. Read size is too big",
tp->path_name); tp->path_name);
ret = -EINVAL; ret = -EINVAL;
goto test_fail; goto test_fail;
} else if (remaining_size == 0) {
if (tp->read_size > tp->expected_size) {
pr_err("read test failed: %s. Server returned more data than expected file size (%u > %u)",
tp->path_name, tp->read_size, tp->expected_size);
ret = -EINVAL;
goto test_fail;
}
} else if (remaining_size > 0 && priv->read_data_len != 0) { } else if (remaining_size > 0 && priv->read_data_len != 0) {
priv->read_offset += priv->read_data_len; priv->read_offset += priv->read_data_len;
@@ -825,11 +834,20 @@ static int isobusfs_cli_test_rf_req(struct isobusfs_priv *priv, bool *complete)
goto test_fail; goto test_fail;
test_start_time = current_time; test_start_time = current_time;
break; break;
} else if (remaining_size > 0 && priv->read_data_len == 0 && tp->expect_pass) { } else if (remaining_size > 0 && priv->read_data_len == 0) {
pr_err("read test failed: %s. Read size is zero, but expected more data: %zd", if (tp->read_size > tp->expected_size &&
tp->path_name, remaining_size); tp->read_size - remaining_size == tp->expected_size) {
ret = -EINVAL; /* this is acceptable case when read size
goto test_fail; * is larger than actual file size
*/
pr_info("read test passed: %s. Reached end of file as expected.",
tp->path_name);
} else {
pr_err("read test failed: %s. Server returned zero bytes, but expected more data: %lld",
tp->path_name, (long long)remaining_size);
ret = -EINVAL;
goto test_fail;
}
} }
/* fall troth */ /* fall troth */
+2 -2
View File
@@ -443,8 +443,8 @@ void isobusfs_dump_tx_data(const struct isobusfs_buf_log *buffer)
for (j = 0; j < ISOBUSFS_MIN_TRANSFER_LENGH; ++j) for (j = 0; j < ISOBUSFS_MIN_TRANSFER_LENGH; ++j)
snprintf(data_str + j * 3, 4, "%02X ", entry->data[j]); snprintf(data_str + j * 3, 4, "%02X ", entry->data[j]);
pr_debug("Entry %u: %s Timestamp: %ld.%09ld\n", i, data_str, pr_debug("Entry %u: %s Timestamp: %lld.%09ld\n", i, data_str,
entry->ts.tv_sec, entry->ts.tv_nsec); (long long)entry->ts.tv_sec, entry->ts.tv_nsec);
} }
} }
+2 -1
View File
@@ -322,7 +322,8 @@ typedef enum {
} log_level_t; } log_level_t;
void isobusfs_log_level_set(log_level_t level); void isobusfs_log_level_set(log_level_t level);
void isobusfs_log(log_level_t level, const char *fmt, ...); void isobusfs_log(log_level_t level, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
void isobusfs_set_interactive(bool interactive); void isobusfs_set_interactive(bool interactive);
void isobusfs_print_log_buffer(void); void isobusfs_print_log_buffer(void);
+6 -6
View File
@@ -39,7 +39,7 @@ struct isobusfs_cm_fss {
uint8_t status; uint8_t status;
uint8_t num_open_files; uint8_t num_open_files;
uint8_t reserved[5]; uint8_t reserved[5];
}; } __attribute__((__packed__));
/** /**
* C.1.3 Client Connection Maintenance * C.1.3 Client Connection Maintenance
@@ -58,7 +58,7 @@ struct isobusfs_cm_ccm {
uint8_t fs_function; uint8_t fs_function;
uint8_t version; uint8_t version;
uint8_t reserved[6]; uint8_t reserved[6];
}; } __attribute__((__packed__));
/** /**
* C.1.4 Get File Server Properties * C.1.4 Get File Server Properties
@@ -75,7 +75,7 @@ struct isobusfs_cm_ccm {
struct isobusfs_cm_get_fs_props_req { struct isobusfs_cm_get_fs_props_req {
uint8_t fs_function; uint8_t fs_function;
uint8_t reserved[7]; uint8_t reserved[7];
}; } __attribute__((__packed__));
/* File Server Capabilities */ /* File Server Capabilities */
/* server support removable volumes */ /* server support removable volumes */
@@ -104,7 +104,7 @@ struct isobusfs_cm_get_fs_props_resp {
uint8_t max_open_files; uint8_t max_open_files;
uint8_t fs_capabilities; uint8_t fs_capabilities;
uint8_t reserved[4]; uint8_t reserved[4];
}; } __attribute__((__packed__));
#define ISOBUSFS_VOL_MODE_PREP_TO_REMOVE BIT(1) #define ISOBUSFS_VOL_MODE_PREP_TO_REMOVE BIT(1)
#define ISOBUSFS_VOL_MODE_USED_BY_CLIENT BIT(0) #define ISOBUSFS_VOL_MODE_USED_BY_CLIENT BIT(0)
@@ -130,7 +130,7 @@ struct isobusfs_cm_vol_stat_req {
uint8_t volume_mode; uint8_t volume_mode;
__le16 name_len; __le16 name_len;
char name[ISOBUSFS_MAX_VOLUME_NAME_LENGTH]; char name[ISOBUSFS_MAX_VOLUME_NAME_LENGTH];
}; } __attribute__((__packed__));
enum isobusfs_vol_status { enum isobusfs_vol_status {
@@ -169,7 +169,7 @@ struct isobusfs_cm_vol_stat_res {
uint8_t error_code; uint8_t error_code;
__le16 name_len; __le16 name_len;
char name[ISOBUSFS_MAX_VOLUME_NAME_LENGTH]; char name[ISOBUSFS_MAX_VOLUME_NAME_LENGTH];
}; } __attribute__((__packed__));
#endif /* ISOBUSFS_CMN_CM_H */ #endif /* ISOBUSFS_CMN_CM_H */
+4 -4
View File
@@ -23,7 +23,7 @@ struct isobusfs_dh_get_cd_req {
uint8_t fs_function; uint8_t fs_function;
uint8_t tan; uint8_t tan;
uint8_t reserved[6]; uint8_t reserved[6];
}; } __attribute__((__packed__));
/** /**
* C.2.2.3 Get Current Directory Response * C.2.2.3 Get Current Directory Response
@@ -50,7 +50,7 @@ struct isobusfs_dh_get_cd_res {
__le32 free_space; __le32 free_space;
__le16 name_len; __le16 name_len;
uint8_t name[]; uint8_t name[];
}; } __attribute__((__packed__));
/** /**
* C.2.3.2 Change Current Directory Request * C.2.3.2 Change Current Directory Request
@@ -71,7 +71,7 @@ struct isobusfs_dh_ccd_req {
uint8_t tan; uint8_t tan;
__le16 name_len; __le16 name_len;
uint8_t name[]; uint8_t name[];
}; } __attribute__((__packed__));
/** /**
* C.2.3.3 Change Current Directory Response * C.2.3.3 Change Current Directory Response
@@ -101,7 +101,7 @@ struct isobusfs_dh_ccd_res {
uint8_t tan; uint8_t tan;
uint8_t error_code; uint8_t error_code;
uint8_t reserved[5]; uint8_t reserved[5];
}; } __attribute__((__packed__));
#endif /* _ISOBUSFS_CMN_DH_H */ #endif /* _ISOBUSFS_CMN_DH_H */
+11 -11
View File
@@ -105,7 +105,7 @@ struct isobusfs_fa_openf_req {
uint8_t flags; uint8_t flags;
__le16 name_len; __le16 name_len;
uint8_t name[]; uint8_t name[];
}; } __attribute__((__packed__));
/** /**
* C.3.3.3 Open File Response * C.3.3.3 Open File Response
@@ -141,7 +141,7 @@ struct isobusfs_fa_openf_res {
uint8_t handle; uint8_t handle;
uint8_t attributes; uint8_t attributes;
uint8_t reserved[3]; uint8_t reserved[3];
}; } __attribute__((__packed__));
/* B.17 Position mode */ /* B.17 Position mode */
/* From the beginning of the file */ /* From the beginning of the file */
@@ -168,7 +168,7 @@ struct isobusfs_fa_seekf_req {
uint8_t handle; uint8_t handle;
uint8_t position_mode; uint8_t position_mode;
__le32 offset; __le32 offset;
}; } __attribute__((__packed__));
/** /**
* C.3.4.2 Seek File Response * C.3.4.2 Seek File Response
@@ -195,7 +195,7 @@ struct isobusfs_fa_seekf_res {
uint8_t error_code; uint8_t error_code;
uint8_t reserved; uint8_t reserved;
__le32 position; __le32 position;
}; } __attribute__((__packed__));
/** /**
* C.3.5.2 Read File Request * C.3.5.2 Read File Request
@@ -220,7 +220,7 @@ struct isobusfs_fa_readf_req {
uint8_t handle; uint8_t handle;
__le16 count; __le16 count;
uint8_t reserved[3]; uint8_t reserved[3];
}; } __attribute__((__packed__));
/** /**
* C.3.5.3 Read File Response (Handle-referenced file) * C.3.5.3 Read File Response (Handle-referenced file)
@@ -250,7 +250,7 @@ struct isobusfs_read_file_response {
uint8_t error_code; uint8_t error_code;
__le16 count; __le16 count;
uint8_t data[]; uint8_t data[];
}; } __attribute__((__packed__));
/** /**
* C.3.5.4 Read Directory Response (Handle-referenced directory) * C.3.5.4 Read Directory Response (Handle-referenced directory)
@@ -280,7 +280,7 @@ struct isobusfs_read_dir_response {
uint8_t error_code; uint8_t error_code;
__le16 count; __le16 count;
uint8_t data[]; uint8_t data[];
}; } __attribute__((__packed__));
/** /**
* C.3.6.2 Write File Request * C.3.6.2 Write File Request
@@ -303,7 +303,7 @@ struct isobusfs_write_file_request {
uint8_t handle; uint8_t handle;
__le16 count; __le16 count;
uint8_t data[]; uint8_t data[];
}; } __attribute__((__packed__));
/** /**
* C.3.6.3 Write File Response * C.3.6.3 Write File Response
@@ -333,7 +333,7 @@ struct isobusfs_write_file_response {
uint8_t error_code; uint8_t error_code;
__le16 count; __le16 count;
uint8_t reserved[3]; uint8_t reserved[3];
}; } __attribute__((__packed__));
/** /**
* C.3.7.1 Close File Request * C.3.7.1 Close File Request
@@ -354,7 +354,7 @@ struct isobusfs_close_file_request {
uint8_t tan; uint8_t tan;
uint8_t handle; uint8_t handle;
uint8_t reserved[5]; uint8_t reserved[5];
}; } __attribute__((__packed__));
/** /**
* C.3.7.2 Close File Response * C.3.7.2 Close File Response
@@ -378,7 +378,7 @@ struct isobusfs_close_file_res {
uint8_t tan; uint8_t tan;
uint8_t error_code; uint8_t error_code;
uint8_t reserved[6]; uint8_t reserved[6];
}; } __attribute__((__packed__));
#endif /* _LINUX_ISOBUS_FS_H */ #endif /* _LINUX_ISOBUS_FS_H */
+10 -10
View File
@@ -32,7 +32,7 @@ struct isobusfs_move_file_request {
/* Variable length data follows */ /* Variable length data follows */
/* uint8_t src_path[]; */ /* uint8_t src_path[]; */
/* uint8_t dst_path[]; */ /* uint8_t dst_path[]; */
}; } __attribute__((__packed__));
/** /**
* C.4.2.3 Move File Response * C.4.2.3 Move File Response
@@ -64,7 +64,7 @@ struct isobusfs_move_file_response {
uint8_t tan; uint8_t tan;
uint8_t error_code; uint8_t error_code;
uint8_t reserved[5]; uint8_t reserved[5];
}; } __attribute__((__packed__));
/** /**
* C.4.3.1 Delete File Request * C.4.3.1 Delete File Request
@@ -87,7 +87,7 @@ struct isobusfs_delete_file_request {
uint8_t mode; uint8_t mode;
__le16 path_len; __le16 path_len;
uint8_t path[]; uint8_t path[];
}; } __attribute__((__packed__));
/** /**
@@ -118,7 +118,7 @@ struct isobusfs_delete_file_response {
uint8_t tan; uint8_t tan;
uint8_t error_code; uint8_t error_code;
uint8_t reserved[5]; uint8_t reserved[5];
}; } __attribute__((__packed__));
/** /**
* C.4.4.2 Get File Attributes Request * C.4.4.2 Get File Attributes Request
@@ -139,7 +139,7 @@ struct isobusfs_get_file_attributes_request {
uint8_t tan; uint8_t tan;
__le16 pathname_len; __le16 pathname_len;
uint8_t pathname[]; uint8_t pathname[];
}; } __attribute__((__packed__));
/** /**
* C.4.4.3 Get File Attributes Response * C.4.4.3 Get File Attributes Response
@@ -171,7 +171,7 @@ struct isobusfs_get_file_attributes_response {
uint8_t error_code; uint8_t error_code;
uint8_t attributes; uint8_t attributes;
__le32 file_size; __le32 file_size;
}; } __attribute__((__packed__));
/** /**
* C.4.5.2 Set File Attributes Request * C.4.5.2 Set File Attributes Request
@@ -194,7 +194,7 @@ struct isobusfs_set_file_attributes_request {
uint8_t attributes; uint8_t attributes;
__le16 name_length; __le16 name_length;
uint8_t name[]; /* Variable length */ uint8_t name[]; /* Variable length */
}; } __attribute__((__packed__));
/** /**
* C.4.5.3 Set File Attributes Response * C.4.5.3 Set File Attributes Response
@@ -225,7 +225,7 @@ struct isobusfs_set_file_attributes_response {
uint8_t tan; uint8_t tan;
uint8_t error_code; uint8_t error_code;
uint8_t reserved[5]; uint8_t reserved[5];
}; } __attribute__((__packed__));
/** /**
* C.4.6.2 Get File Date & Time Request * C.4.6.2 Get File Date & Time Request
@@ -246,7 +246,7 @@ struct isobusfs_get_file_date_time_request {
uint8_t tan; uint8_t tan;
__le16 name_length; __le16 name_length;
uint8_t name[]; /* Variable length */ uint8_t name[]; /* Variable length */
}; } __attribute__((__packed__));
/** /**
* C.4.6.2 Get File Date & Time Response * C.4.6.2 Get File Date & Time Response
@@ -278,6 +278,6 @@ struct isobusfs_get_file_date_time_response {
uint8_t error_code; uint8_t error_code;
__le16 date; __le16 date;
__le16 time; __le16 time;
}; } __attribute__((__packed__));
#endif /* _LINUX_ISOBUS_FS_H */ #endif /* _LINUX_ISOBUS_FS_H */
+2 -2
View File
@@ -29,7 +29,7 @@ struct isobusfs_va_init_vol_req {
uint8_t volume_flags; uint8_t volume_flags;
__le16 name_len; __le16 name_len;
uint8_t name[]; uint8_t name[];
}; } __attribute__((__packed__));
/** /**
* C.5.2.3 Initialize Volume Response * C.5.2.3 Initialize Volume Response
@@ -62,6 +62,6 @@ struct isobusfs_va_init_vol_res {
uint8_t tan; uint8_t tan;
uint8_t error_code; uint8_t error_code;
uint8_t reserved[4]; uint8_t reserved[4];
}; } __attribute__((__packed__));
#endif /* _ISOBUSFS_CMN_VA_H */ #endif /* _ISOBUSFS_CMN_VA_H */
+9 -2
View File
@@ -20,6 +20,7 @@
*/ */
#include <errno.h> #include <errno.h>
#include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -473,8 +474,14 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
req_name_len = le16toh(req->name_len); req_name_len = le16toh(req->name_len);
pr_debug("< rx volume status request. mode: %x, length: %d, name: %s", /* the volume name has to fit into the received message */
req->volume_mode, req_name_len, req->name); if (req_name_len > msg->len - offsetof(struct isobusfs_cm_vol_stat_req, name)) {
pr_warn("volume name length exceeds message length");
return ISOBUSFS_ERR_MALFORMED_REQUEST;
}
pr_debug("< rx volume status request. mode: %x, length: %zu, name: %.*s",
req->volume_mode, req_name_len, (int)req_name_len, req->name);
client = isobusfs_srv_get_client_by_msg(priv, msg); client = isobusfs_srv_get_client_by_msg(priv, msg);
if (!client) { if (!client) {
+1 -1
View File
@@ -97,7 +97,7 @@ int isobusfs_srv_fss_send(struct isobusfs_srv_priv *priv)
} }
if (time_diff < -ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) { if (time_diff < -ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) {
pr_warn("too late to send next fs status message: %ld ms", pr_warn("too late to send next fs status message: %" PRId64 " ms",
time_diff); time_diff);
} }
+14 -4
View File
@@ -132,7 +132,7 @@ int isobusfs_check_current_dir_access(struct isobusfs_srv_priv *priv,
return ret; return ret;
pr_debug("convert ISOBUS FS path to linux path: %.*s -> %s", pr_debug("convert ISOBUS FS path to linux path: %.*s -> %s",
path_size, path, linux_path); (int)path_size, path, linux_path);
ret = isobusfs_cmn_dh_validate_dir_path(linux_path, false); ret = isobusfs_cmn_dh_validate_dir_path(linux_path, false);
if (ret < 0) if (ret < 0)
@@ -170,10 +170,13 @@ static int isobusfs_srv_dh_current_dir_res(struct isobusfs_srv_priv *priv,
switch (ret) { switch (ret) {
case -ENOENT: case -ENOENT:
error_code = ISOBUSFS_ERR_FILE_ORPATH_NOT_FOUND; error_code = ISOBUSFS_ERR_FILE_ORPATH_NOT_FOUND;
break;
case -ENOMEDIUM: case -ENOMEDIUM:
error_code = ISOBUSFS_ERR_VOLUME_NOT_INITIALIZED; error_code = ISOBUSFS_ERR_VOLUME_NOT_INITIALIZED;
break;
case -ENOMEM: case -ENOMEM:
error_code = ISOBUSFS_ERR_OUT_OF_MEM; error_code = ISOBUSFS_ERR_OUT_OF_MEM;
break;
default: default:
error_code = ISOBUSFS_ERR_OTHER; error_code = ISOBUSFS_ERR_OTHER;
} }
@@ -657,15 +660,22 @@ static int isobusfs_srv_dh_ccd_res(struct isobusfs_srv_priv *priv,
uint8_t error_code = ISOBUSFS_ERR_SUCCESS; uint8_t error_code = ISOBUSFS_ERR_SUCCESS;
struct isobusfs_srv_client *client; struct isobusfs_srv_client *client;
struct isobusfs_dh_ccd_res res; struct isobusfs_dh_ccd_res res;
uint16_t name_len = le16toh(req->name_len);
size_t abs_path_len; size_t abs_path_len;
char *abs_path; char *abs_path;
int ret; int ret;
/* the path name has to fit into the received message */
if (name_len > msg->len - sizeof(*req)) {
pr_warn("path name length exceeds message length");
return -EINVAL;
}
/* /*
* We assume, the relative path stored in res->name is not longer * We assume, the relative path stored in res->name is not longer
* than absolute path * than absolute path
*/ */
if (req->name_len > ISOBUSFS_SRV_MAX_PATH_LEN) { if (name_len > ISOBUSFS_SRV_MAX_PATH_LEN) {
pr_warn("path too long"); pr_warn("path too long");
return -EINVAL; return -EINVAL;
} }
@@ -684,10 +694,10 @@ static int isobusfs_srv_dh_ccd_res(struct isobusfs_srv_priv *priv,
} }
pr_debug("< rx change current directory request from client 0x%2x: %.*s. Current directory: %s", pr_debug("< rx change current directory request from client 0x%2x: %.*s. Current directory: %s",
client->addr, req->name_len, req->name, client->current_dir); client->addr, name_len, req->name, client->current_dir);
/* Normalize provided string and convert it to absolute ISOBUS FS path */ /* Normalize provided string and convert it to absolute ISOBUS FS path */
ret = isobusfs_convert_relative_to_absolute(priv, client->current_dir, ret = isobusfs_convert_relative_to_absolute(priv, client->current_dir,
(char *)req->name, req->name_len, (char *)req->name, name_len,
abs_path, abs_path_len); abs_path, abs_path_len);
if (ret < 0) if (ret < 0)
goto process_error; goto process_error;
+248 -49
View File
@@ -45,6 +45,9 @@ static int isobusfs_srv_add_file(struct isobusfs_srv_priv *priv,
} }
priv->handles[j].path = strdup(path); priv->handles[j].path = strdup(path);
if (!priv->handles[j].path)
return -ENOMEM;
priv->handles[j].fd = fd; priv->handles[j].fd = fd;
priv->handles[j].dir = dir; priv->handles[j].dir = dir;
@@ -108,6 +111,28 @@ isobusfs_srv_get_handle(struct isobusfs_srv_priv *priv, int handle)
return &priv->handles[handle]; return &priv->handles[handle];
} }
/*
* Return the handle only when it is in use and has been opened by the
* requesting client. Otherwise return NULL.
*/
static struct isobusfs_srv_handles *
isobusfs_srv_get_client_handle(struct isobusfs_srv_priv *priv,
struct isobusfs_srv_client *client, int handle)
{
struct isobusfs_srv_handles *hdl = isobusfs_srv_get_handle(priv, handle);
unsigned int i;
if (!hdl || !hdl->path)
return NULL;
for (i = 0; i < ARRAY_SIZE(hdl->clients); i++) {
if (hdl->clients[i] == client)
return hdl;
}
return NULL;
}
static int isobusfs_srv_release_handle(struct isobusfs_srv_priv *priv, static int isobusfs_srv_release_handle(struct isobusfs_srv_priv *priv,
struct isobusfs_srv_client *client, struct isobusfs_srv_client *client,
int handle) int handle)
@@ -137,6 +162,7 @@ static int isobusfs_srv_release_handle(struct isobusfs_srv_priv *priv,
closedir(hdl->dir); closedir(hdl->dir);
else else
close(hdl->fd); close(hdl->fd);
free(hdl->path);
memset(hdl, 0, sizeof(*hdl)); memset(hdl, 0, sizeof(*hdl));
priv->handles_count--; priv->handles_count--;
} }
@@ -261,7 +287,7 @@ static int isobusfs_srv_fa_open_file(struct isobusfs_srv_priv *priv,
return ret; return ret;
pr_debug("convert ISOBUS FS path to linux path: %.*s -> %s", pr_debug("convert ISOBUS FS path to linux path: %.*s -> %s",
path_len, path, linux_path); (int)path_len, path, linux_path);
/* Determine open flags based on the requested access type */ /* Determine open flags based on the requested access type */
switch (flags & ISOBUSFS_FA_OPEN_MASK) { switch (flags & ISOBUSFS_FA_OPEN_MASK) {
@@ -495,15 +521,119 @@ static int check_access_with_base(const char *base_dir,
return access(full_path, mode); return access(full_path, mode);
} }
/*
* ISO 11783-13:2021 B.21 and B.15:
* Filters directory entries that can be returned in a Read File response
* for directory handles while collecting the attributes and name length.
*/
/**
* isobusfs_srv_dir_entry_visible() - Filter visible directory entries.
* @handle: Directory handle for access checks.
* @entry: Directory entry to inspect.
* @file_stat: Stat buffer to fill for the entry.
* @entry_name_len: Returns entry name length on success.
* @attributes: Returns computed attributes on success.
*
* ISO 11783-13:2021 B.21 and B.15 define the directory entry layout and
* attributes. This helper skips entries that are not readable or too long
* and returns attributes for the entry that will be serialized.
*
* Return: true when the entry should be emitted, false otherwise.
*/
static bool isobusfs_srv_dir_entry_visible(struct isobusfs_srv_handles *handle,
const struct dirent *entry,
struct stat *file_stat,
size_t *entry_name_len,
uint8_t *attributes)
{
if (check_access_with_base(handle->path, entry->d_name, R_OK) != 0)
return false;
if (fstatat(handle->fd, entry->d_name, file_stat, 0) < 0)
return false;
*entry_name_len = strlen(entry->d_name);
if (*entry_name_len > ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH)
return false;
if (S_ISDIR(file_stat->st_mode))
*attributes |= ISOBUSFS_ATTR_DIRECTORY;
if (check_access_with_base(handle->path, entry->d_name, W_OK) != 0)
*attributes |= ISOBUSFS_ATTR_READ_ONLY;
return true;
}
/*
* ISO 11783-13:2021 C.3.4.2 and C.3.5.2:
* Directory offsets/counts are in entries, so advance the directory stream
* by visible entries only and report EOF if the entry offset is past the end.
*/
/**
* isobusfs_srv_dir_skip_entries() - Advance directory stream by entries.
* @handle: Directory handle to reposition.
* @offset: Entry offset to seek to.
*
* ISO 11783-13:2021 C.3.4.2 and C.3.5.2 state directory offsets/counts are in
* entries. This helper advances by visible entries only.
*
* Return: ISOBUSFS_ERR_SUCCESS or a protocol error code.
*/
static int isobusfs_srv_dir_skip_entries(struct isobusfs_srv_handles *handle,
int32_t offset)
{
struct dirent *entry;
int32_t skipped = 0;
rewinddir(handle->dir);
while (skipped < offset && (entry = readdir(handle->dir)) != NULL) {
struct stat file_stat;
size_t entry_name_len = 0;
uint8_t attributes = 0;
if (!isobusfs_srv_dir_entry_visible(handle, entry, &file_stat,
&entry_name_len,
&attributes))
continue;
skipped++;
}
if (offset > 0 && skipped < offset)
return ISOBUSFS_ERR_END_OF_FILE;
return ISOBUSFS_ERR_SUCCESS;
}
/**
* isobusfs_srv_read_directory() - Read directory entries into a response buffer.
* @handle: Directory handle to read.
* @buffer: Output buffer for directory entries.
* @max_bytes: Maximum payload bytes allowed in the response.
* @max_entries: Maximum number of entries to return.
* @readed_size: Returns payload size in bytes.
* @entries_read: Returns number of entries serialized.
*
* ISO 11783-13:2021 C.3.5.2: directory Count is entry based. This function
* encodes up to @max_entries entries while respecting @max_bytes.
*
* Return: ISOBUSFS_ERR_SUCCESS or a protocol error code.
*/
static int isobusfs_srv_read_directory(struct isobusfs_srv_handles *handle, static int isobusfs_srv_read_directory(struct isobusfs_srv_handles *handle,
uint8_t *buffer, size_t count, uint8_t *buffer, size_t max_bytes,
ssize_t *readed_size) uint16_t max_entries,
ssize_t *readed_size,
uint16_t *entries_read)
{ {
DIR *dir = handle->dir; DIR *dir = handle->dir;
struct dirent *entry; struct dirent *entry;
size_t pos = 0; size_t pos = 0;
int ret;
/* /*
* ISO 11783-13:2021 C.3.5.2:
* Directory offsets are entry indices, not byte positions.
* Position the directory stream to the previously stored offset (handle->dir_pos). * Position the directory stream to the previously stored offset (handle->dir_pos).
* *
* Handling Changes in Directory Contents: * Handling Changes in Directory Contents:
@@ -519,13 +649,18 @@ static int isobusfs_srv_read_directory(struct isobusfs_srv_handles *handle,
* either returning an error or restarting from the beginning of the directory, depending * either returning an error or restarting from the beginning of the directory, depending
* on the application's requirements. * on the application's requirements.
*/ */
for (int i = 0; i < handle->dir_pos && if (handle->dir_pos < 0) {
(entry = readdir(dir)) != NULL; i++) { pr_err("Directory handle in invalid state (pos=%d)\n",
/* Iterating to the desired position */ handle->dir_pos);
return ISOBUSFS_ERR_INVALID_HANDLE;
} }
ret = isobusfs_srv_dir_skip_entries(handle, handle->dir_pos);
if (ret != ISOBUSFS_ERR_SUCCESS)
return ret;
/* /*
* Directory Entry Layout: * Directory Entry Layout (ISO 11783-13:2021 B.21):
* This loop reads directory entries and encodes them into a buffer. * This loop reads directory entries and encodes them into a buffer.
* Each entry in the buffer follows the format specified in ISO 11783-13:2021. * Each entry in the buffer follows the format specified in ISO 11783-13:2021.
* *
@@ -550,26 +685,23 @@ static int isobusfs_srv_read_directory(struct isobusfs_srv_handles *handle,
* The handle->dir_pos is incremented after processing each entry, marking * The handle->dir_pos is incremented after processing each entry, marking
* the current position in the directory stream for subsequent reads. * the current position in the directory stream for subsequent reads.
*/ */
while ((entry = readdir(dir)) != NULL) { *entries_read = 0;
while ((entry = readdir(dir)) != NULL &&
(*entries_read) < max_entries) {
size_t entry_name_len, entry_total_len; size_t entry_name_len, entry_total_len;
__le16 file_date, file_time; __le16 file_date, file_time;
uint8_t attributes = 0;
struct stat file_stat; struct stat file_stat;
uint8_t attributes = 0;
__le32 size; __le32 size;
if (check_access_with_base(handle->path, entry->d_name, R_OK) != 0) if (!isobusfs_srv_dir_entry_visible(handle, entry, &file_stat,
continue; /* Skip this entry if it's not readable */ &entry_name_len,
&attributes))
if (fstatat(handle->fd, entry->d_name, &file_stat, 0) < 0)
continue; /* Skip this entry on error */
entry_name_len = strlen(entry->d_name);
if (entry_name_len > ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH)
continue; continue;
entry_total_len = 1 + entry_name_len + 1 + 2 + 2 + 4; entry_total_len = 1 + entry_name_len + 1 + 2 + 2 + 4;
if (pos + entry_total_len > count) if (pos + entry_total_len > max_bytes)
break; break;
buffer[pos++] = (uint8_t)entry_name_len; buffer[pos++] = (uint8_t)entry_name_len;
@@ -577,10 +709,6 @@ static int isobusfs_srv_read_directory(struct isobusfs_srv_handles *handle,
memcpy(buffer + pos, entry->d_name, entry_name_len); memcpy(buffer + pos, entry->d_name, entry_name_len);
pos += entry_name_len; pos += entry_name_len;
if (S_ISDIR(file_stat.st_mode))
attributes |= ISOBUSFS_ATTR_DIRECTORY;
if (check_access_with_base(handle->path, entry->d_name, W_OK) != 0)
attributes |= ISOBUSFS_ATTR_READ_ONLY;
buffer[pos++] = attributes; buffer[pos++] = attributes;
file_date = htole16(convert_to_file_date(file_stat.st_mtime)); file_date = htole16(convert_to_file_date(file_stat.st_mtime));
@@ -594,9 +722,11 @@ static int isobusfs_srv_read_directory(struct isobusfs_srv_handles *handle,
size = htole32(file_stat.st_size); size = htole32(file_stat.st_size);
memcpy(buffer + pos, &size, sizeof(size)); memcpy(buffer + pos, &size, sizeof(size));
pos += sizeof(size); pos += sizeof(size);
(*entries_read)++;
} }
*readed_size = pos; *readed_size = pos;
handle->dir_pos += *entries_read;
return 0; return 0;
} }
@@ -609,13 +739,19 @@ static int isobusfs_srv_fa_rf_req(struct isobusfs_srv_priv *priv,
struct isobusfs_srv_client *client; struct isobusfs_srv_client *client;
struct isobusfs_fa_readf_req *req; struct isobusfs_fa_readf_req *req;
ssize_t readed_size = 0; ssize_t readed_size = 0;
uint16_t entries_read = 0;
uint8_t error_code = 0; uint8_t error_code = 0;
ssize_t send_size; ssize_t send_size;
bool res_allocated = false;
size_t alloc_size;
size_t max_bytes = 0;
uint16_t count = 0;
int ret = 0; int ret = 0;
int count; bool is_dir = false;
req = (struct isobusfs_fa_readf_req *)msg->buf; req = (struct isobusfs_fa_readf_req *)msg->buf;
count = le16toh(req->count); count = le16toh(req->count);
res = (struct isobusfs_read_file_response *)&res_fail[0];
pr_debug("< rx: Read File Request. tan: %d, handle: %d, count: %d", pr_debug("< rx: Read File Request. tan: %d, handle: %d, count: %d",
req->tan, req->handle, count); req->tan, req->handle, count);
@@ -627,17 +763,6 @@ static int isobusfs_srv_fa_rf_req(struct isobusfs_srv_priv *priv,
* TODO: currently we are not able to detect support transport mode, * TODO: currently we are not able to detect support transport mode,
* so ETP is assumed. * so ETP is assumed.
*/ */
if (count > ISOBUSFS_MAX_DATA_LENGH)
count = ISOBUSFS_MAX_DATA_LENGH;
res = malloc(sizeof(*res) + count);
if (!res) {
pr_warn("failed to allocate memory");
res = (struct isobusfs_read_file_response *)&res_fail[0];
error_code = ISOBUSFS_ERR_OUT_OF_MEM;
goto send_response;
}
client = isobusfs_srv_get_client_by_msg(priv, msg); client = isobusfs_srv_get_client_by_msg(priv, msg);
if (!client) { if (!client) {
pr_warn("client not found"); pr_warn("client not found");
@@ -645,16 +770,42 @@ static int isobusfs_srv_fa_rf_req(struct isobusfs_srv_priv *priv,
goto send_response; goto send_response;
} }
handle = isobusfs_srv_get_handle(priv, req->handle); handle = isobusfs_srv_get_client_handle(priv, client, req->handle);
if (!handle) { if (!handle) {
pr_warn("failed to find file with handle: %x", req->handle); pr_warn("failed to find file with handle: %x", req->handle);
error_code = ISOBUSFS_ERR_FILE_ORPATH_NOT_FOUND; error_code = ISOBUSFS_ERR_FILE_ORPATH_NOT_FOUND;
goto send_response;
} }
/* Determine whether to read a file or a directory */ /* Determine whether to read a file or a directory */
if (handle->dir) { if (handle->dir) {
ret = isobusfs_srv_read_directory(handle, res->data, count, /* ISO 11783-13:2021 C.3.5.2: count is entry count for directories. */
&readed_size); is_dir = true;
max_bytes = ISOBUSFS_MAX_DATA_LENGH;
} else {
if (count > ISOBUSFS_MAX_DATA_LENGH)
count = ISOBUSFS_MAX_DATA_LENGH;
max_bytes = count;
}
/* the response is padded to ISOBUSFS_MIN_TRANSFER_LENGH (see below) */
alloc_size = sizeof(*res) + max_bytes;
if (alloc_size < ISOBUSFS_MIN_TRANSFER_LENGH)
alloc_size = ISOBUSFS_MIN_TRANSFER_LENGH;
res = malloc(alloc_size);
if (!res) {
pr_warn("failed to allocate memory");
res = (struct isobusfs_read_file_response *)&res_fail[0];
error_code = ISOBUSFS_ERR_OUT_OF_MEM;
goto send_response;
}
res_allocated = true;
if (is_dir) {
ret = isobusfs_srv_read_directory(handle, res->data, max_bytes,
count, &readed_size,
&entries_read);
} else { } else {
ret = isobusfs_srv_read_file(handle, res->data, count, ret = isobusfs_srv_read_file(handle, res->data, count,
&readed_size); &readed_size);
@@ -663,7 +814,10 @@ static int isobusfs_srv_fa_rf_req(struct isobusfs_srv_priv *priv,
if (ret < 0) { if (ret < 0) {
error_code = ret; error_code = ret;
readed_size = 0; readed_size = 0;
} else if (count != 0 && readed_size == 0) { entries_read = 0;
} else if (count != 0 &&
((is_dir && entries_read == 0) ||
(!is_dir && readed_size == 0))) {
error_code = ISOBUSFS_ERR_END_OF_FILE; error_code = ISOBUSFS_ERR_END_OF_FILE;
} }
@@ -673,11 +827,18 @@ send_response:
ISOBUSFS_FA_F_READ_FILE_RES); ISOBUSFS_FA_F_READ_FILE_RES);
res->tan = req->tan; res->tan = req->tan;
res->error_code = error_code; res->error_code = error_code;
res->count = htole16(readed_size); if (is_dir)
res->count = htole16(entries_read);
else
res->count = htole16(readed_size);
send_size = sizeof(*res) + readed_size; send_size = sizeof(*res) + readed_size;
if (send_size < ISOBUSFS_MIN_TRANSFER_LENGH) if (send_size < ISOBUSFS_MIN_TRANSFER_LENGH) {
/* fill the unused bytes with 0xff */
memset((uint8_t *)res + send_size, 0xff,
ISOBUSFS_MIN_TRANSFER_LENGH - send_size);
send_size = ISOBUSFS_MIN_TRANSFER_LENGH; send_size = ISOBUSFS_MIN_TRANSFER_LENGH;
}
/* send to socket */ /* send to socket */
ret = isobusfs_srv_sendto(priv, msg, res, send_size); ret = isobusfs_srv_sendto(priv, msg, res, send_size);
@@ -686,11 +847,12 @@ send_response:
goto free_res; goto free_res;
} }
pr_debug("> tx: Read File Response. Error code: %d (%s), read size: %d", pr_debug("> tx: Read File Response. Error code: %d (%s), read size: %zd",
error_code, isobusfs_error_to_str(error_code), readed_size); error_code, isobusfs_error_to_str(error_code), readed_size);
free_res: free_res:
free(res); if (res_allocated)
free(res);
return ret; return ret;
} }
@@ -754,19 +916,56 @@ static int isobusfs_srv_seek(struct isobusfs_srv_priv *priv,
return ISOBUSFS_ERR_SUCCESS; return ISOBUSFS_ERR_SUCCESS;
} }
/**
* isobusfs_srv_seek_directory() - Seek a directory by entry index.
* @handle: Directory handle to seek.
* @offset: Entry index to seek to.
*
* ISO 11783-13:2021 C.3.4.2 defines directory offsets as entry indices.
*
* Return: ISOBUSFS_ERR_SUCCESS or a protocol error code.
*/
static int isobusfs_srv_seek_directory(struct isobusfs_srv_handles *handle, static int isobusfs_srv_seek_directory(struct isobusfs_srv_handles *handle,
int32_t offset) int32_t offset)
{ {
DIR *dir = fdopendir(handle->fd); int32_t current_pos = handle->dir_pos;
int ret;
if (!dir) if (!handle->dir)
return ISOBUSFS_ERR_OTHER; return ISOBUSFS_ERR_OTHER;
rewinddir(dir); /* Check if handle is in valid state */
if (current_pos < 0) {
pr_err("Cannot seek directory in invalid state (pos=%d)\n",
current_pos);
return ISOBUSFS_ERR_INVALID_HANDLE;
}
for (int32_t i = 0; i < offset; i++) { /* Validate requested offset */
if (readdir(dir) == NULL) if (offset < 0) {
return ISOBUSFS_ERR_END_OF_FILE; pr_err("Invalid seek offset: %d\n", offset);
return ISOBUSFS_ERR_INVALID_REQUESTED_LENGHT;
}
/*
* ISO 11783-13:2021 C.3.4.2:
* Directory offsets are entry indices. If we fail to seek, restore
* the previous entry position since the position shall not change on error.
*/
ret = isobusfs_srv_dir_skip_entries(handle, offset);
if (ret != ISOBUSFS_ERR_SUCCESS) {
int restore_ret;
restore_ret = isobusfs_srv_dir_skip_entries(handle, current_pos);
if (restore_ret != ISOBUSFS_ERR_SUCCESS) {
pr_warn("Failed to restore directory position after seek failure: %d -> %d",
current_pos, restore_ret);
/* Directory stream is now in undefined state.
* Mark position as invalid.
*/
handle->dir_pos = -1;
}
return ret;
} }
handle->dir_pos = offset; handle->dir_pos = offset;
@@ -796,7 +995,7 @@ static int isobusfs_srv_fa_sf_req(struct isobusfs_srv_priv *priv,
goto send_response; goto send_response;
} }
handle = isobusfs_srv_get_handle(priv, req->handle); handle = isobusfs_srv_get_client_handle(priv, client, req->handle);
if (!handle) { if (!handle) {
pr_warn("failed to find handle: %x", req->handle); pr_warn("failed to find handle: %x", req->handle);
error_code = ISOBUSFS_ERR_INVALID_HANDLE; error_code = ISOBUSFS_ERR_INVALID_HANDLE;
+6
View File
@@ -618,6 +618,12 @@ int main(int argc, char *argv[])
} }
break; break;
case J1939_PGN_ADDRESS_COMMANDED: case J1939_PGN_ADDRESS_COMMANDED:
/* 8 bytes NAME + 1 byte new source address */
if (ret < 9)
break;
/* only accept valid unicast addresses */
if (dat[8] > J1939_MAX_UNICAST_ADDR)
break;
if (!host_is_little_endian()) if (!host_is_little_endian())
bswap(dat, 8); bswap(dat, 8);
memcpy(&cmd_name, dat, 8); memcpy(&cmd_name, dat, 8);
+8
View File
@@ -664,6 +664,7 @@ int snprintf_long_canframe(char *buf, size_t size, union cfu *cu, int view)
return offset; return offset;
} }
/* check CANERR_BUFFSZ in lib.h when changing the error frame strings */
static const char *error_classes[] = { static const char *error_classes[] = {
"tx-timeout", "tx-timeout",
"lost-arbitration", "lost-arbitration",
@@ -844,6 +845,13 @@ int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf
if (!sep) if (!sep)
sep = defsep; sep = defsep;
/* the size of the provided buffer has to fit CANERR_BUFFSZ (see lib.h) */
if (len < CANERR_BUFFSZ) {
if (len)
buf[0] = 0; /* empty terminated string */
return 0;
}
for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) { for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) {
mask = 1 << i; mask = 1 << i;
if (class & mask) { if (class & mask) {
+21 -2
View File
@@ -238,11 +238,30 @@ int snprintf_long_canframe(char *buf, size_t size, union cfu *cu, int view);
* data bytes is limited to 64 to fit terminal output use-cases. * data bytes is limited to 64 to fit terminal output use-cases.
*/ */
int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
const char *sep);
/* /*
* Creates a CAN error frame output in user readable format. * Creates a CAN error frame output in user readable format.
*
* buf: buffer for the output string
* len: size of the provided buffer buf in bytes (incl. string termination)
* sep: separator string between the error classes (NULL => default ",")
*
* The buffer size len needs to be at least CANERR_BUFFSZ bytes - otherwise
* an empty string is returned.
*
* Calculation of the required buffer size:
* The longest error frame content (all error classes and details set) has
* 465 characters plus the string termination = 466 bytes. Additionally up
* to 9 separators are inserted which results in 466 + 9 * strlen(sep) bytes,
* e.g. 466 + 9 * 2 = 484 bytes for "\n\t" (as used in candump).
* With CANERR_BUFFSZ = 800 the separator must not exceed 37 characters.
*
* When the error frame content (the strings in lib.c) is changed, the current
* values have to be re-calculated and CANERR_BUFFSZ has to be adapted if needed.
*/ */
#define CANERR_BUFFSZ 800
int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
const char *sep);
/** /**
* timespec_diff_ms - calculate timespec difference in milliseconds * timespec_diff_ms - calculate timespec difference in milliseconds
+12 -23
View File
@@ -58,6 +58,7 @@ static int pty2can(int pty, int socket, struct can_filter *fi,
static char buf[200]; static char buf[200];
char replybuf[10]; /* for answers to received commands */ char replybuf[10]; /* for answers to received commands */
unsigned int ptr; unsigned int ptr;
unsigned int msglen; /* length of the current SLCAN message w/o '\r' */
struct can_frame frame; struct can_frame frame;
int ret, i; int ret, i;
static unsigned int rxoffset = 0; /* points to the end of an received incomplete SLCAN message */ static unsigned int rxoffset = 0; /* points to the end of an received incomplete SLCAN message */
@@ -102,6 +103,7 @@ rx_restart:
return 0; return 0;
} }
msglen = tmp;
cmd = buf[0]; cmd = buf[0];
buf[nbytes] = 0; buf[nbytes] = 0;
@@ -112,10 +114,11 @@ rx_restart:
pr_debug("%c", buf[tmp]); pr_debug("%c", buf[tmp]);
pr_debug("\n"); pr_debug("\n");
/* terminate the current SLCAN message to not read the following content */
buf[msglen] = 0;
/* check for filter configuration commands */ /* check for filter configuration commands */
if (cmd == 'm' || cmd == 'M') { if (cmd == 'm' || cmd == 'M') {
buf[9] = 0; /* terminate filter string */
ptr = 9;
#if 0 #if 0
/* the filter is no SocketCAN filter :-( */ /* the filter is no SocketCAN filter :-( */
@@ -140,14 +143,12 @@ rx_restart:
/* check for timestamp on/off command */ /* check for timestamp on/off command */
if (cmd == 'Z') { if (cmd == 'Z') {
*tstamp = buf[1] & 0x01; *tstamp = buf[1] & 0x01;
ptr = 2;
goto rx_out_ack; goto rx_out_ack;
} }
/* check for 'O'pen command */ /* check for 'O'pen command */
if (cmd == 'O') { if (cmd == 'O') {
setsockopt(socket, SOL_CAN_RAW, CAN_RAW_FILTER, fi, sizeof(struct can_filter)); setsockopt(socket, SOL_CAN_RAW, CAN_RAW_FILTER, fi, sizeof(struct can_filter));
ptr = 1;
*is_open = 1; *is_open = 1;
goto rx_out_ack; goto rx_out_ack;
} }
@@ -155,7 +156,6 @@ rx_restart:
/* check for 'C'lose command */ /* check for 'C'lose command */
if (cmd == 'C') { if (cmd == 'C') {
setsockopt(socket, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); setsockopt(socket, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
ptr = 1;
*is_open = 0; *is_open = 0;
goto rx_out_ack; goto rx_out_ack;
} }
@@ -164,14 +164,12 @@ rx_restart:
if (cmd == 'V') { if (cmd == 'V') {
sprintf(replybuf, "V1013\r"); sprintf(replybuf, "V1013\r");
tmp = strlen(replybuf); tmp = strlen(replybuf);
ptr = 1;
goto rx_out; goto rx_out;
} }
/* check for 'v'ersion command */ /* check for 'v'ersion command */
if (cmd == 'v') { if (cmd == 'v') {
sprintf(replybuf, "v1014\r"); sprintf(replybuf, "v1014\r");
tmp = strlen(replybuf); tmp = strlen(replybuf);
ptr = 1;
goto rx_out; goto rx_out;
} }
@@ -179,7 +177,6 @@ rx_restart:
if (cmd == 'N') { if (cmd == 'N') {
sprintf(replybuf, "N4242\r"); sprintf(replybuf, "N4242\r");
tmp = strlen(replybuf); tmp = strlen(replybuf);
ptr = 1;
goto rx_out; goto rx_out;
} }
@@ -187,29 +184,23 @@ rx_restart:
if (cmd == 'F') { if (cmd == 'F') {
sprintf(replybuf, "F00\r"); sprintf(replybuf, "F00\r");
tmp = strlen(replybuf); tmp = strlen(replybuf);
ptr = 1;
goto rx_out; goto rx_out;
} }
/* correctly answer unsupported commands */ /* correctly answer unsupported commands */
if (cmd == 'U') { if (cmd == 'U') {
ptr = 2;
goto rx_out_ack; goto rx_out_ack;
} }
if (cmd == 'S') { if (cmd == 'S') {
ptr = 2;
goto rx_out_ack; goto rx_out_ack;
} }
if (cmd == 's') { if (cmd == 's') {
ptr = 5;
goto rx_out_ack; goto rx_out_ack;
} }
if (cmd == 'P' || cmd == 'A') { if (cmd == 'P' || cmd == 'A') {
ptr = 1;
goto rx_out_nack; goto rx_out_nack;
} }
if (cmd == 'X') { if (cmd == 'X') {
ptr = 2;
if (buf[1] & 0x01) if (buf[1] & 0x01)
goto rx_out_ack; goto rx_out_ack;
else else
@@ -217,16 +208,18 @@ rx_restart:
} }
/* catch unknown commands */ /* catch unknown commands */
if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R')) { if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R'))
ptr = nbytes - 1;
goto rx_out_nack; goto rx_out_nack;
}
if (cmd & 0x20) /* tiny chars 'r' 't' => SFF */ if (cmd & 0x20) /* tiny chars 'r' 't' => SFF */
ptr = 4; /* dlc position tiiid */ ptr = 4; /* dlc position tiiid */
else else
ptr = 9; /* dlc position Tiiiiiiiid */ ptr = 9; /* dlc position Tiiiiiiiid */
/* the CAN ID has to fit into the current SLCAN message */
if (ptr > msglen)
goto rx_out_nack;
memset(&frame.data, 0, 8); /* clear data[] */ memset(&frame.data, 0, 8); /* clear data[] */
if ((cmd | 0x20) == 'r' && buf[ptr] != '0') { if ((cmd | 0x20) == 'r' && buf[ptr] != '0') {
@@ -249,7 +242,6 @@ rx_restart:
buf[ptr] = frame.can_dlc; /* restore following byte */ buf[ptr] = frame.can_dlc; /* restore following byte */
frame.can_dlc = 0; frame.can_dlc = 0;
ptr--; /* we have no dlc component in the violation case */
} else { } else {
if (!(buf[ptr] >= '0' && buf[ptr] < '9')) if (!(buf[ptr] >= '0' && buf[ptr] < '9'))
@@ -277,9 +269,6 @@ rx_restart:
goto rx_out_nack; goto rx_out_nack;
frame.data[i] |= tmp; frame.data[i] |= tmp;
} }
/* point to last real data */
if (frame.can_dlc)
ptr--;
} }
ret = write(socket, &frame, sizeof(frame)); ret = write(socket, &frame, sizeof(frame));
@@ -303,8 +292,8 @@ rx_out:
} }
/* check if there is another command in this buffer */ /* check if there is another command in this buffer */
if (nbytes > ptr + 1) { if (nbytes > msglen + 1) {
for (tmp = 0, ptr++; ptr + tmp < nbytes; tmp++) for (tmp = 0, ptr = msglen + 1; ptr + tmp < nbytes; tmp++)
buf[tmp] = buf[ptr + tmp]; buf[tmp] = buf[ptr + tmp];
nbytes = tmp; nbytes = tmp;
goto rx_restart; goto rx_restart;