// SPDX-License-Identifier: LGPL-2.0-only // SPDX-FileCopyrightText: 2023 Oleksij Rempel #ifndef _ISOBUSFS_H_ #define _ISOBUSFS_H_ #include #include #include #include #include #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_ */