344 lines
10 KiB
C
344 lines
10 KiB
C
// SPDX-License-Identifier: LGPL-2.0-only
|
|
// SPDX-FileCopyrightText: 2023 Oleksij Rempel <linux@rempel-privat.de>
|
|
|
|
#ifndef _ISOBUSFS_H_
|
|
#define _ISOBUSFS_H_
|
|
|
|
#include <stdint.h>
|
|
#include <endian.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <linux/can.h>
|
|
#include <linux/kernel.h>
|
|
#include "../libj1939.h"
|
|
#include "../lib.h"
|
|
|
|
/* ISO 11783-13:2021 - C.1.1.a File Server to Client PGN */
|
|
#define ISOBUSFS_PGN_FS_TO_CL 0x0ab00 /* 43766 */
|
|
/* ISO 11783-13:2021 - C.1.1.b Client to File Server PGN */
|
|
#define ISOBUSFS_PGN_CL_TO_FS 0x0aa00 /* 43520 */
|
|
|
|
#define ISOBUSFS_PRIO_DEFAULT 7
|
|
#define ISOBUSFS_PRIO_FSS 5
|
|
#define ISOBUSFS_PRIO_ACK 6
|
|
#define ISOBUSFS_MAX_OPENED_FILES 255
|
|
#define ISOBUSFS_MAX_SHORT_FILENAME_LENGH 12 /* 12 chars */
|
|
#define ISOBUSFS_MAX_LONG_FILENAME_LENGH 31 /* 31 chars */
|
|
/* ISO 11783-13:2021 - C.3.5.1 Maximal transfer size for TP (Transport Protocol) */
|
|
#define ISOBUSFS_TP_MAX_TRANSFER_SIZE 1780
|
|
/* ISO 11783-13:2021 - C.3.5.1 Maximal transfer size for ETP (Extended Transport Protocol) */
|
|
#define ISOBUSFS_ETP_MAX_TRANSFER_SIZE 65530
|
|
#define ISOBUSFS_MAX_DATA_LENGH 65530 /* Bytes */
|
|
#define ISOBUSFS_MAX_TRANSFER_LENGH (6 + ISOBUSFS_MAX_DATA_LENGH)
|
|
#define ISOBUSFS_MIN_TRANSFER_LENGH 8
|
|
#define ISOBUSFS_CLIENT_TIMEOUT 6000 /* ms */
|
|
#define ISOBUSFS_FS_TIMEOUT 6000 /* ms */
|
|
#define ISOBUSFS_MAX_BUF_ENTRIES 10
|
|
#define ISOBUSFS_MAX_PATH_NAME_LENGTH ISOBUSFS_MAX_DATA_LENGH
|
|
|
|
/* not documented, take some max value */
|
|
#define ISOBUSFS_SRV_MAX_VOLUMES 10
|
|
/* ISO 11783-13:2021 A.2.2.3 Volumes */
|
|
#define ISOBUSFS_SRV_MAX_VOLUME_NAME_LEN 254
|
|
#define ISOBUSFS_MAX_VOLUME_NAME_LENGTH 254
|
|
#define ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH 255
|
|
/* not documented, take some max value */
|
|
#define ISOBUSFS_SRV_MAX_PATH_LEN 4096
|
|
|
|
#define ISOBUSFS_FILE_HANDLE_ERROR 255
|
|
|
|
/* ISO 11783-3:2018 - 5.4.5 Acknowledgment */
|
|
#define ISOBUS_PGN_ACK 0x0e800 /* 59392 */
|
|
|
|
enum isobusfs_ack_ctrl {
|
|
ISOBUS_ACK_CTRL_ACK = 0,
|
|
ISOBUS_ACK_CTRL_NACK = 1,
|
|
};
|
|
|
|
struct isobusfs_nack {
|
|
uint8_t ctrl;
|
|
uint8_t group_function;
|
|
uint8_t reserved[2];
|
|
uint8_t address_nack;
|
|
uint8_t pgn_nack[3];
|
|
};
|
|
|
|
/* ISO 11783-13:2021 - Annex B.1 Command Groups (CG) */
|
|
enum isobusfs_cg {
|
|
ISOBUSFS_CG_CONNECTION_MANAGMENT = 0,
|
|
ISOBUSFS_CG_DIRECTORY_HANDLING = 1,
|
|
ISOBUSFS_CG_FILE_ACCESS = 2,
|
|
ISOBUSFS_CG_FILE_HANDLING = 3,
|
|
ISOBUSFS_CG_VOLUME_HANDLING = 4,
|
|
};
|
|
|
|
#define ISOBUSFS_CM_F_CCM_RATE 2000 /* ms */
|
|
|
|
/* Connection Management functions: */
|
|
/* ISO 11783-13:2021 - C.1.* Connection Management - Client to File Server
|
|
* functions:
|
|
*/
|
|
enum isobusfs_cm_cl_to_fs_function {
|
|
/* ISO 11783-13:2021 - C.1.3 Client Connection Maintenance */
|
|
ISOBUSFS_CM_F_CC_MAINTENANCE = 0,
|
|
/* ISO 11783-13:2021 - C.1.4 Get File Server Properties */
|
|
ISOBUSFS_CM_GET_FS_PROPERTIES = 1,
|
|
/* ISO 11783-13:2021 - C.1.6 Volume Status Request */
|
|
ISOBUSFS_CM_VOLUME_STATUS_REQ = 2,
|
|
};
|
|
|
|
/* ISO 11783-13:2021 - C.1.* Connection Management - File Server to client
|
|
* functions:
|
|
*/
|
|
enum isobusfs_cm_fs_to_cl_function {
|
|
/* ISO 11783-13:2021 - C.1.2 File Server Status */
|
|
ISOBUSFS_CM_F_FS_STATUS = 0,
|
|
/* ISO 11783-13:2021 - C.1.5 Get File Server Properties Response */
|
|
ISOBUSFS_CM_GET_FS_PROPERTIES_RES = 1,
|
|
/* ISO 11783-13:2021 - C.1.7 Volume Status Response */
|
|
ISOBUSFS_CM_VOLUME_STATUS_RES = 2,
|
|
};
|
|
|
|
/* Directory Handling functions: */
|
|
/* send by server: */
|
|
enum isobusfs_dh_fs_to_cl_function {
|
|
ISOBUSFS_DH_F_GET_CURRENT_DIR_RES = 0,
|
|
ISOBUSFS_DH_F_CHANGE_CURRENT_DIR_RES = 1,
|
|
};
|
|
|
|
/* send by client: */
|
|
enum isobusfs_dh_cl_to_fs_function {
|
|
ISOBUSFS_DH_F_GET_CURRENT_DIR_REQ = 0,
|
|
ISOBUSFS_DH_F_CHANGE_CURRENT_DIR_REQ = 1,
|
|
};
|
|
|
|
/* File Access functions: */
|
|
/* send by server: */
|
|
enum isobusfs_fa_fs_to_cl_function {
|
|
ISOBUSFS_FA_F_OPEN_FILE_RES = 0,
|
|
ISOBUSFS_FA_F_SEEK_FILE_RES = 1,
|
|
ISOBUSFS_FA_F_READ_FILE_RES = 2,
|
|
ISOBUSFS_FA_F_WRITE_FILE_RES = 3,
|
|
ISOBUSFS_FA_F_CLOSE_FILE_RES = 4,
|
|
};
|
|
|
|
/* send by client: */
|
|
enum isobusfs_fa_cl_to_fs_function {
|
|
ISOBUSFS_FA_F_OPEN_FILE_REQ = 0,
|
|
ISOBUSFS_FA_F_SEEK_FILE_REQ = 1,
|
|
ISOBUSFS_FA_F_READ_FILE_REQ = 2,
|
|
ISOBUSFS_FA_F_WRITE_FILE_REQ = 3,
|
|
ISOBUSFS_FA_F_CLOSE_FILE_REQ = 4,
|
|
};
|
|
|
|
/* File Handling functions: */
|
|
/* send by server: */
|
|
enum isobusfs_fh_fs_to_cl_function {
|
|
ISOBUSFS_FH_F_MOVE_FILE_RES = 0,
|
|
ISOBUSFS_FH_F_DELETE_FILE_RES = 1,
|
|
ISOBUSFS_FH_F_GET_FILE_ATTR_RES = 2,
|
|
ISOBUSFS_FH_F_SET_FILE_ATTR_RES = 3,
|
|
ISOBUSFS_FH_F_GET_FILE_DATETIME_RES = 4,
|
|
};
|
|
|
|
/* send by client: */
|
|
enum isobusfs_fh_cl_to_fs_function {
|
|
ISOBUSFS_FH_F_MOVE_FILE_REQ = 0,
|
|
ISOBUSFS_FH_F_DELETE_FILE_REQ = 1,
|
|
ISOBUSFS_FH_F_GET_FILE_ATTR_REQ = 2,
|
|
ISOBUSFS_FH_F_SET_FILE_ATTR_REQ = 3,
|
|
ISOBUSFS_FH_F_GET_FILE_DATETIME_REQ = 4,
|
|
};
|
|
|
|
/* Volume Access functions: */
|
|
/* Preparing or repairing the volume for files and directory structures.
|
|
* These commands should be limited to initial setup, intended to be used by
|
|
* service tool clients only.
|
|
*/
|
|
/* send by server: */
|
|
/* Initialize Volume: Prepare the volume to accept files and directories. All
|
|
* data will be lost upon completion of this command.
|
|
*/
|
|
enum isobusfs_va_fs_to_cl_function {
|
|
ISOBUSFS_VA_F_INITIALIZE_VOLUME_RES = 0,
|
|
};
|
|
|
|
/* send by client: */
|
|
enum isobusfs_va_cl_to_fs_function {
|
|
/* Initialize Volume: Prepare the volume to accept files and directories.
|
|
* All data will be lost upon completion of this command.
|
|
*/
|
|
ISOBUSFS_VA_F_INITIALIZE_VOLUME_REQ = 0,
|
|
};
|
|
|
|
/* ISO 11783-13:2021 - Annex B.9 Error Code */
|
|
enum isobusfs_error {
|
|
/* Success */
|
|
ISOBUSFS_ERR_SUCCESS = 0,
|
|
/* Access Denied */
|
|
ISOBUSFS_ERR_ACCESS_DENIED = 1,
|
|
/* Invalid Access */
|
|
ISOBUSFS_ERR_INVALID_ACCESS = 2,
|
|
/* Too many files open */
|
|
ISOBUSFS_ERR_TOO_MANY_FILES_OPEN = 3,
|
|
/* File or path not found */
|
|
ISOBUSFS_ERR_FILE_ORPATH_NOT_FOUND = 4,
|
|
/* Invalid handle */
|
|
ISOBUSFS_ERR_INVALID_HANDLE = 5,
|
|
/* Invalid given source name */
|
|
ISOBUSFS_ERR_INVALID_SRC_NAME = 6,
|
|
/* Invalid given destination name */
|
|
ISOBUSFS_ERR_INVALID_DST_NAME = 7,
|
|
/* Volume out of free space */
|
|
ISOBUSFS_ERR_NO_SPACE = 8,
|
|
/* Failure during a write operation */
|
|
ISOBUSFS_ERR_ON_WRITE = 9,
|
|
/* Media is not present */
|
|
ISOBUSFS_ERR_MEDIA_IS_NOT_PRESENT = 10,
|
|
/* Failure during a read operation */
|
|
ISOBUSFS_ERR_ON_READ = 11,
|
|
/* Function not supported */
|
|
ISOBUSFS_ERR_FUNC_NOT_SUPPORTED = 12,
|
|
/* Volume is possibly not initialized */
|
|
ISOBUSFS_ERR_VOLUME_NOT_INITIALIZED = 13,
|
|
/* Invalid request length */
|
|
ISOBUSFS_ERR_INVALID_REQUESTED_LENGHT = 42,
|
|
/* Out of memory */
|
|
ISOBUSFS_ERR_OUT_OF_MEM = 43,
|
|
/* Any other error */
|
|
ISOBUSFS_ERR_OTHER = 44,
|
|
/* End of file reached, will only be reported when file pointer is at
|
|
* end of file
|
|
*/
|
|
ISOBUSFS_ERR_END_OF_FILE = 45,
|
|
/* TAN error:
|
|
* Same TAN, but different request compared to the previous one (change
|
|
* in content or size).
|
|
*/
|
|
ISOBUSFS_ERR_TAN_ERR = 46,
|
|
/* Malformed request:
|
|
* Message is shorter than expected. If the message is too short to
|
|
* provide a TAN (less than 2 bytes), the TAN shall be set to 0xff in
|
|
* the response.
|
|
*/
|
|
ISOBUSFS_ERR_MALFORMED_REQUEST = 47,
|
|
};
|
|
|
|
/* recursive buffer entry */
|
|
struct isobusfs_buf {
|
|
uint8_t data[ISOBUSFS_MIN_TRANSFER_LENGH];
|
|
struct timespec ts;
|
|
};
|
|
|
|
struct isobusfs_buf_log {
|
|
struct isobusfs_buf entries[ISOBUSFS_MAX_BUF_ENTRIES];
|
|
unsigned int index;
|
|
};
|
|
|
|
struct isobusfs_stats {
|
|
int err;
|
|
uint32_t tskey_sch;
|
|
uint32_t tskey_ack;
|
|
uint32_t send;
|
|
};
|
|
|
|
struct isobusfs_msg {
|
|
uint8_t buf[ISOBUSFS_MAX_TRANSFER_LENGH];
|
|
size_t buf_size;
|
|
ssize_t len; /* length of received message */
|
|
struct sockaddr_can peername;
|
|
socklen_t peer_addr_len;
|
|
int sock;
|
|
};
|
|
|
|
struct isobusfs_err_msg {
|
|
struct sock_extended_err *serr;
|
|
struct scm_timestamping *tss;
|
|
struct isobusfs_stats *stats;
|
|
};
|
|
|
|
int isobusfs_recv_err(int sock, struct isobusfs_err_msg *emsg);
|
|
|
|
/*
|
|
* min()/max()/clamp() macros that also do
|
|
* strict type-checking.. See the
|
|
* "unnecessary" pointer comparison.
|
|
*/
|
|
#define min(x, y) ({ \
|
|
typeof(x) _min1 = (x); \
|
|
typeof(y) _min2 = (y); \
|
|
(void) (&_min1 == &_min2); \
|
|
_min1 < _min2 ? _min1 : _min2; })
|
|
|
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
|
|
|
static inline int isobusfs_buf_to_cmd(uint8_t *buf)
|
|
{
|
|
return (buf[0] & 0xf0) >> 4;
|
|
}
|
|
|
|
static inline int isobusfs_buf_to_function(uint8_t *buf)
|
|
{
|
|
return (buf[0] & 0xf);
|
|
}
|
|
|
|
static inline uint8_t isobusfs_cg_function_to_buf(enum isobusfs_cg cg,
|
|
uint8_t func)
|
|
{
|
|
return (func & 0xf) | ((cg & 0xf) << 4);
|
|
}
|
|
|
|
const char *isobusfs_error_to_str(enum isobusfs_error err);
|
|
enum isobusfs_error linux_error_to_isobusfs_error(int linux_err);
|
|
|
|
void isobusfs_send_nack(int sock, struct isobusfs_msg *msg);
|
|
void isobufs_store_tx_data(struct isobusfs_buf_log *buffer, uint8_t *data);
|
|
void isobusfs_dump_tx_data(const struct isobusfs_buf_log *buffer);
|
|
int isobusfs_sendto(int sock, const void *data, size_t len,
|
|
const struct sockaddr_can *addr,
|
|
struct isobusfs_buf_log *isobusfs_tx_buffer);
|
|
int isobusfs_send(int sock, const void *data, size_t len,
|
|
struct isobusfs_buf_log *isobusfs_tx_buffer);
|
|
|
|
void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size,
|
|
size_t x);
|
|
|
|
int isobusfs_cmn_configure_socket_filter(int sock, pgn_t pgn);
|
|
int isobusfs_cmn_configure_error_queue(int sock);
|
|
int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr);
|
|
int isobusfs_cmn_set_linger(int sock);
|
|
|
|
/* ============ directory handling ============ */
|
|
int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable);
|
|
|
|
/* ============ logging ============ */
|
|
|
|
typedef enum {
|
|
LOG_LEVEL_INT,
|
|
LOG_LEVEL_ERROR,
|
|
LOG_LEVEL_WARN,
|
|
LOG_LEVEL_INFO,
|
|
LOG_LEVEL_DEBUG,
|
|
} log_level_t;
|
|
|
|
void isobusfs_log_level_set(log_level_t level);
|
|
void isobusfs_log(log_level_t level, const char *fmt, ...);
|
|
void isobusfs_set_interactive(bool interactive);
|
|
void isobusfs_print_log_buffer(void);
|
|
|
|
/* undefine kernel logging macros */
|
|
#undef pr_int
|
|
#undef pr_err
|
|
#undef pr_warn
|
|
#undef pr_info
|
|
#undef pr_debug
|
|
|
|
/* pr_int - print for interactive session */
|
|
#define pr_int(fmt, ...) isobusfs_log(LOG_LEVEL_INT, fmt, ##__VA_ARGS__)
|
|
#define pr_err(fmt, ...) isobusfs_log(LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
|
|
#define pr_warn(fmt, ...) isobusfs_log(LOG_LEVEL_WARN, fmt, ##__VA_ARGS__)
|
|
#define pr_info(fmt, ...) isobusfs_log(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
|
|
#define pr_debug(fmt, ...) isobusfs_log(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
|
|
|
|
#endif /* !_ISOBUSFS_H_ */
|