Files
can-utils/isobusfs/isobusfs_cli_fa.c
T
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

431 lines
11 KiB
C

// SPDX-License-Identifier: LGPL-2.0-only
// SPDX-FileCopyrightText: 2023 Oleksij Rempel <linux@rempel-privat.de>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "isobusfs_cli.h"
#include "isobusfs_cmn_fa.h"
int isobusfs_cli_fa_sf_req(struct isobusfs_priv *priv, uint8_t handle,
uint8_t position_mode, int32_t offset)
{
struct isobusfs_fa_seekf_req req;
int ret;
req.fs_function = isobusfs_cg_function_to_buf(ISOBUSFS_CG_FILE_ACCESS,
ISOBUSFS_FA_F_SEEK_FILE_REQ);
req.tan = isobusfs_cli_get_next_tan(priv);
req.handle = handle;
req.position_mode = position_mode;
req.offset = htole32(offset);
priv->state = ISOBUSFS_CLI_STATE_WAIT_SF_RESP;
ret = isobusfs_send(priv->sock_main, &req, sizeof(req),
&priv->tx_buf_log);
if (ret < 0) {
pr_warn("failed to send Seek File Request: %d (%s)", ret,
strerror(ret));
return ret;
}
pr_debug("> tx: Seek File Request for handle: %x, position mode: %d, offset: %d",
req.handle, req.position_mode, req.offset);
return ret;
}
static int isobusfs_cli_fa_sf_res_log(struct isobusfs_priv *priv,
struct isobusfs_msg *msg,
void *ctx, int error)
{
struct isobusfs_fa_seekf_res *res =
(struct isobusfs_fa_seekf_res *)msg;
if (!isobusfs_cli_tan_is_valid(res->tan, priv)) {
priv->state = ISOBUSFS_CLI_STATE_SF_FAIL;
return -EINVAL;
}
if (res->error_code) {
priv->state = ISOBUSFS_CLI_STATE_SF_FAIL;
pr_warn("< rx: Seek File Error - Error code: %d",
res->error_code);
return -EIO;
}
priv->read_offset = le32toh(res->position);
priv->state = ISOBUSFS_CLI_STATE_SF_DONE;
pr_debug("< rx: Seek File Success, position: %d", res->position);
return 0;
}
int isobusfs_cli_send_and_register_fa_sf_event(struct isobusfs_priv *priv,
uint8_t handle,
uint8_t position_mode,
int32_t offset,
isobusfs_event_callback cb,
void *ctx)
{
struct isobusfs_event event;
uint8_t fs_function;
int ret;
ret = isobusfs_cli_fa_sf_req(priv, handle, position_mode, offset);
if (ret < 0)
return ret;
fs_function =
isobusfs_cg_function_to_buf(ISOBUSFS_CG_FILE_ACCESS,
ISOBUSFS_FA_F_SEEK_FILE_RES);
if (cb)
event.cb = cb;
else
event.cb = isobusfs_cli_fa_sf_res_log;
event.ctx = ctx;
isobusfs_cli_prepare_response_event(&event, priv->sock_main,
fs_function);
return isobusfs_cli_register_event(priv, &event);
}
int isobusfs_cli_fa_rf_req(struct isobusfs_priv *priv, uint8_t handle,
uint16_t count)
{
struct isobusfs_fa_readf_req req;
int ret;
req.fs_function = isobusfs_cg_function_to_buf(ISOBUSFS_CG_FILE_ACCESS,
ISOBUSFS_FA_F_READ_FILE_REQ);
req.tan = isobusfs_cli_get_next_tan(priv);
req.handle = handle;
req.count = htole16(count);
memset(req.reserved, 0xff, sizeof(req.reserved));
priv->state = ISOBUSFS_CLI_STATE_WAIT_RF_RESP;
ret = isobusfs_send(priv->sock_main, &req, sizeof(req), &priv->tx_buf_log);
if (ret < 0) {
ret = -errno;
pr_warn("failed to send Read File Request: %d (%s)", ret, strerror(ret));
return ret;
}
pr_debug("> tx: Read File Request for handle: %x, size: %d", req.handle, count);
return ret;
}
static int isobusfs_cli_fa_rf_res_log(struct isobusfs_priv *priv,
struct isobusfs_msg *msg,
void *ctx, int error)
{
struct isobusfs_read_file_response *res =
(struct isobusfs_read_file_response *)msg->buf;
if (priv->state != ISOBUSFS_CLI_STATE_WAIT_RF_RESP) {
pr_warn("invalid state: %i (expected %i)", priv->state,
ISOBUSFS_CLI_STATE_WAIT_RF_RESP);
return -EINVAL;
}
if (!isobusfs_cli_tan_is_valid(res->tan, priv)) {
priv->state = ISOBUSFS_CLI_STATE_RF_FAIL;
} else if (res->error_code && res->error_code != ISOBUSFS_ERR_END_OF_FILE) {
pr_warn("read file failed with error code: %i", res->error_code);
priv->state = ISOBUSFS_CLI_STATE_RF_FAIL;
} else {
if (priv->read_data) {
pr_err("read data buffer not empty");
free(priv->read_data);
}
priv->read_data_len = le16toh(res->count);
priv->read_data = malloc(priv->read_data_len);
if (!priv->read_data) {
pr_err("failed to allocate memory for data");
priv->state = ISOBUSFS_CLI_STATE_RF_FAIL;
} else {
memcpy(priv->read_data, res->data, priv->read_data_len);
priv->state = ISOBUSFS_CLI_STATE_RF_DONE;
}
}
pr_debug("< rx: Read File Response. Error code: %i", res->error_code);
return 0;
}
int isobusfs_cli_send_and_register_fa_rf_event(struct isobusfs_priv *priv,
uint8_t handle,
uint16_t count,
isobusfs_event_callback cb,
void *ctx)
{
struct isobusfs_event event;
uint8_t fs_function;
int ret;
ret = isobusfs_cli_fa_rf_req(priv, handle, count);
if (ret < 0)
return ret;
fs_function =
isobusfs_cg_function_to_buf(ISOBUSFS_CG_FILE_ACCESS,
ISOBUSFS_FA_F_READ_FILE_RES);
if (cb)
event.cb = cb;
else
event.cb = isobusfs_cli_fa_rf_res_log;
event.ctx = ctx;
isobusfs_cli_prepare_response_event(&event, priv->sock_main,
fs_function);
return isobusfs_cli_register_event(priv, &event);
}
int isobusfs_cli_fa_cf_req(struct isobusfs_priv *priv, uint8_t handle)
{
struct isobusfs_close_file_request req;
int ret;
req.fs_function = isobusfs_cg_function_to_buf(ISOBUSFS_CG_FILE_ACCESS,
ISOBUSFS_FA_F_CLOSE_FILE_REQ);
req.tan = isobusfs_cli_get_next_tan(priv);
req.handle = handle;
memset(req.reserved, 0xff, sizeof(req.reserved));
priv->state = ISOBUSFS_CLI_STATE_WAIT_CF_RESP;
ret = isobusfs_send(priv->sock_main, &req, sizeof(req), &priv->tx_buf_log);
if (ret < 0) {
ret = -errno;
pr_warn("failed to send Close File request: %d (%s)", ret, strerror(ret));
return ret;
}
pr_debug("> tx: Close File Request for handle: %x", req.handle);
return ret;
}
static int isobusfs_cli_fa_cf_res_log(struct isobusfs_priv *priv,
struct isobusfs_msg *msg,
void *ctx, int error)
{
struct isobusfs_close_file_res *res =
(struct isobusfs_close_file_res *)msg->buf;
if (priv->state != ISOBUSFS_CLI_STATE_WAIT_CF_RESP) {
pr_warn("invalid state: %i (expected %i)", priv->state,
ISOBUSFS_CLI_STATE_WAIT_CF_RESP);
return -EINVAL;
}
if (!isobusfs_cli_tan_is_valid(res->tan, priv)) {
priv->state = ISOBUSFS_CLI_STATE_CF_FAIL;
} else if (res->error_code != 0) {
pr_warn("ccd failed with error code: %i", res->error_code);
priv->state = ISOBUSFS_CLI_STATE_CF_FAIL;
} else {
priv->state = ISOBUSFS_CLI_STATE_CF_DONE;
}
pr_debug("< rx: Close File Response. Error code: %i",
res->error_code);
return 0;
}
int isobusfs_cli_send_and_register_fa_cf_event(struct isobusfs_priv *priv,
uint8_t handle,
isobusfs_event_callback cb,
void *ctx)
{
struct isobusfs_event event;
uint8_t fs_function;
int ret;
ret = isobusfs_cli_fa_cf_req(priv, handle);
if (ret < 0)
return ret;
fs_function =
isobusfs_cg_function_to_buf(ISOBUSFS_CG_FILE_ACCESS,
ISOBUSFS_FA_F_CLOSE_FILE_RES);
if (cb)
event.cb = cb;
else
event.cb = isobusfs_cli_fa_cf_res_log;
event.ctx = ctx;
isobusfs_cli_prepare_response_event(&event, priv->sock_main,
fs_function);
return isobusfs_cli_register_event(priv, &event);
}
int isobusfs_cli_fa_of_req(struct isobusfs_priv *priv, const char *name,
size_t name_len, uint8_t flags)
{
struct isobusfs_fa_openf_req *req;
size_t req_len = sizeof(*req) + name_len;
size_t padding_size = 0;
int ret;
if (name_len > ISOBUSFS_MAX_PATH_NAME_LENGTH) {
pr_warn("path name too long: %zu, max is %i", name_len,
ISOBUSFS_MAX_PATH_NAME_LENGTH);
return -EINVAL;
}
if (req_len < ISOBUSFS_MIN_TRANSFER_LENGH) {
/* Update the buffer size accordingly */
padding_size = ISOBUSFS_MIN_TRANSFER_LENGH - req_len;
req_len = ISOBUSFS_MIN_TRANSFER_LENGH;
}
req = malloc(req_len);
if (!req) {
pr_err("failed to allocate memory for ccd request");
return -ENOMEM;
}
req->fs_function = isobusfs_cg_function_to_buf(ISOBUSFS_CG_FILE_ACCESS,
ISOBUSFS_FA_F_OPEN_FILE_REQ);
req->tan = isobusfs_cli_get_next_tan(priv);
req->flags = flags;
memcpy(&req->name[0], name, name_len);
req->name_len = htole16(name_len);
if (padding_size) {
/* Fill the rest of the res structure with 0xff */
memset(((uint8_t *)req) + req_len - padding_size, 0xff,
padding_size);
}
priv->handle = ISOBUSFS_FILE_HANDLE_ERROR;
priv->state = ISOBUSFS_CLI_STATE_WAIT_OF_RESP;
ret = isobusfs_send(priv->sock_main, req, req_len, &priv->tx_buf_log);
if (ret < 0) {
ret = -errno;
pr_warn("failed to send ccd request: %d (%s)",
ret, strerror(ret));
goto free_req;
}
pr_debug("> tx: Open File Request for %s, with flags: %x", name,
req->flags);
free_req:
free(req);
return ret;
}
static int isobusfs_cli_fa_open_file_res_log(struct isobusfs_priv *priv,
struct isobusfs_msg *msg,
void *ctx, int error)
{
struct isobusfs_fa_openf_res *res =
(struct isobusfs_fa_openf_res *)msg->buf;
if (priv->state != ISOBUSFS_CLI_STATE_WAIT_OF_RESP) {
pr_warn("invalid state: %i (expected %i)", priv->state,
ISOBUSFS_CLI_STATE_WAIT_OF_RESP);
return -EINVAL;
}
if (!isobusfs_cli_tan_is_valid(res->tan, priv)) {
priv->state = ISOBUSFS_CLI_STATE_OF_FAIL;
} else if (res->error_code != 0) {
pr_warn("open file request failed with error code: %i", res->error_code);
priv->state = ISOBUSFS_CLI_STATE_OF_FAIL;
} else if (res->handle == ISOBUSFS_FILE_HANDLE_ERROR) {
pr_warn("open file request didn't failed with error code, but with handle");
priv->state = ISOBUSFS_CLI_STATE_OF_FAIL;
} else {
priv->state = ISOBUSFS_CLI_STATE_OF_DONE;
priv->handle = res->handle;
}
pr_debug("< rx: Open File Response. Error code: %i",
res->error_code);
return 0;
}
int isobusfs_cli_send_and_register_fa_of_event(struct isobusfs_priv *priv,
const char *name,
size_t name_len,
uint8_t flags,
isobusfs_event_callback cb,
void *ctx)
{
struct isobusfs_event event;
uint8_t fs_function;
int ret;
ret = isobusfs_cli_fa_of_req(priv, name, name_len, flags);
if (ret < 0)
return ret;
fs_function =
isobusfs_cg_function_to_buf(ISOBUSFS_CG_FILE_ACCESS,
ISOBUSFS_FA_F_OPEN_FILE_RES);
if (cb)
event.cb = cb;
else
event.cb = isobusfs_cli_fa_open_file_res_log;
event.ctx = ctx;
isobusfs_cli_prepare_response_event(&event, priv->sock_main,
fs_function);
return isobusfs_cli_register_event(priv, &event);
}
/* Command group: directory handling */
int isobusfs_cli_rx_cg_fa(struct isobusfs_priv *priv,
struct isobusfs_msg *msg)
{
int func = isobusfs_buf_to_function(msg->buf);
int ret = 0;
switch (func) {
case ISOBUSFS_FA_F_OPEN_FILE_RES:
ret = isobusfs_cli_fa_open_file_res_log(priv, msg, NULL, 0);
break;
case ISOBUSFS_FA_F_CLOSE_FILE_RES:
ret = isobusfs_cli_fa_cf_res_log(priv, msg, NULL, 0);
break;
case ISOBUSFS_FA_F_READ_FILE_RES:
ret = isobusfs_cli_fa_rf_res_log(priv, msg, NULL, 0);
break;
case ISOBUSFS_FA_F_SEEK_FILE_RES:
ret = isobusfs_cli_fa_sf_res_log(priv, msg, NULL, 0);
break;
case ISOBUSFS_FA_F_WRITE_FILE_RES:
default:
pr_warn("%s: unsupported function: %i", __func__, func);
/* Not a critical error */
}
return ret;
}