242 lines
6.2 KiB
C
242 lines
6.2 KiB
C
// SPDX-License-Identifier: LGPL-2.0-only
|
|
// SPDX-FileCopyrightText: 2023 Oleksij Rempel <linux@rempel-privat.de>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "isobusfs_cli.h"
|
|
#include "isobusfs_cmn_cm.h"
|
|
|
|
|
|
int isobusfs_cli_volume_status_req(struct isobusfs_priv *priv,
|
|
uint8_t volume_mode,
|
|
uint16_t path_name_length,
|
|
const char *volume_name)
|
|
{
|
|
struct isobusfs_cm_vol_stat_req req;
|
|
size_t req_size;
|
|
int ret;
|
|
|
|
req.fs_function =
|
|
isobusfs_cg_function_to_buf(ISOBUSFS_CG_CONNECTION_MANAGMENT,
|
|
ISOBUSFS_CM_VOLUME_STATUS_REQ);
|
|
|
|
req.volume_mode = volume_mode;
|
|
req.name_len = htole16(path_name_length);
|
|
req_size = sizeof(req) - sizeof(req.name) + path_name_length;
|
|
|
|
memcpy(req.name, volume_name, path_name_length);
|
|
|
|
ret = isobusfs_send(priv->sock_main, &req, req_size, &priv->tx_buf_log);
|
|
if (ret < 0) {
|
|
ret = -errno;
|
|
pr_warn("failed to send volume status request: %d (%s)", ret, strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
priv->state = ISOBUSFS_CLI_STATE_WAIT_VOLUME_STATUS;
|
|
|
|
pr_debug("> tx: volume status request");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int isobusfs_cli_property_req(struct isobusfs_priv *priv)
|
|
{
|
|
uint8_t buf[ISOBUSFS_MIN_TRANSFER_LENGH];
|
|
int ret;
|
|
|
|
/* not used space should be filled with 0xff */
|
|
memset(buf, 0xff, ARRAY_SIZE(buf));
|
|
buf[0] = isobusfs_cg_function_to_buf(ISOBUSFS_CG_CONNECTION_MANAGMENT,
|
|
ISOBUSFS_CM_GET_FS_PROPERTIES);
|
|
|
|
/* send property request */
|
|
ret = isobusfs_send(priv->sock_main, buf, sizeof(buf), &priv->tx_buf_log);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
priv->state = ISOBUSFS_CLI_STATE_WAIT_FS_PROPERTIES;
|
|
|
|
pr_debug("> tx: FS property request");
|
|
return 0;
|
|
}
|
|
|
|
/* ccm section */
|
|
void isobusfs_cli_ccm_init(struct isobusfs_priv *priv)
|
|
{
|
|
struct isobusfs_cm_ccm *ccm = &priv->ccm;
|
|
|
|
ccm->fs_function =
|
|
isobusfs_cg_function_to_buf(ISOBUSFS_CG_CONNECTION_MANAGMENT,
|
|
ISOBUSFS_CM_F_FS_STATUS);
|
|
ccm->version = 2;
|
|
memset(ccm->reserved, 0xFF, sizeof(ccm->reserved));
|
|
}
|
|
|
|
/**
|
|
* isobusfs_cli_ccm_send - send periodic file server status messages
|
|
* @priv: pointer to the isobusfs_priv structure
|
|
*
|
|
* Returns 0 on success, -1 on errors.
|
|
*/
|
|
int isobusfs_cli_ccm_send(struct isobusfs_priv *priv)
|
|
{
|
|
int64_t time_diff;
|
|
int ret;
|
|
|
|
/* Test if it is proper time to send next status message. */
|
|
time_diff = timespec_diff_ms(&priv->cmn.next_send_time,
|
|
&priv->cmn.last_time);
|
|
if (time_diff > ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) {
|
|
/* too early to send next message */
|
|
return 0;
|
|
}
|
|
|
|
if (time_diff < -ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) {
|
|
pr_warn("too late to send next fs status message: %ld ms",
|
|
time_diff);
|
|
}
|
|
|
|
/* Make sure we send the message with the latest stats */
|
|
if (priv->stats.tskey_sch != priv->stats.tskey_ack)
|
|
pr_warn("previous message was not acked");
|
|
|
|
/* send periodic file servers status messages. */
|
|
ret = isobusfs_send(priv->sock_ccm, &priv->ccm, sizeof(priv->ccm),
|
|
&priv->tx_buf_log);
|
|
if (ret < 0) {
|
|
pr_err("sendto() failed: %d (%s)", ret, strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
pr_debug("> tx: ccm version: %d", priv->ccm.version);
|
|
|
|
priv->cmn.next_send_time = priv->cmn.last_time;
|
|
timespec_add_ms(&priv->cmn.next_send_time, 2000);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* detect if FS is timeout */
|
|
void isobusfs_cli_fs_detect_timeout(struct isobusfs_priv *priv)
|
|
{
|
|
int64_t time_diff;
|
|
|
|
if (!priv->fs_is_active)
|
|
return;
|
|
|
|
time_diff = timespec_diff_ms(&priv->cmn.last_time,
|
|
&priv->fs_last_seen);
|
|
if (time_diff > ISOBUSFS_FS_TIMEOUT) {
|
|
pr_debug("file server timeout");
|
|
priv->fs_is_active = false;
|
|
}
|
|
}
|
|
|
|
/* activate FS status if was not active till now */
|
|
static void isobusfs_cli_fs_activate(struct isobusfs_priv *priv)
|
|
{
|
|
if (priv->fs_is_active)
|
|
return;
|
|
|
|
pr_debug("file server detectet");
|
|
priv->fs_is_active = true;
|
|
}
|
|
|
|
static int isobusfs_cli_rx_fs_status(struct isobusfs_priv *priv,
|
|
struct isobusfs_msg *msg)
|
|
{
|
|
struct isobusfs_cm_fss *fs_status = (void *)msg->buf;
|
|
int ret = 0;
|
|
|
|
if (msg->len != sizeof(*fs_status)) {
|
|
pr_warn("wrong message length: %d", msg->len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
isobusfs_cli_fs_activate(priv);
|
|
|
|
priv->fs_last_seen = priv->cmn.last_time;
|
|
pr_debug("< rx: fs status: %x, opened files: %d",
|
|
fs_status->status, fs_status->num_open_files);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* process FS properties response */
|
|
static int isobusfs_cli_rx_fs_property_res(struct isobusfs_priv *priv,
|
|
struct isobusfs_msg *msg)
|
|
{
|
|
struct isobusfs_cm_get_fs_props_resp *fs_prop = (void *)msg->buf;
|
|
int ret = 0;
|
|
|
|
if (priv->state != ISOBUSFS_CLI_STATE_WAIT_FS_PROPERTIES) {
|
|
pr_warn("unexpected fs properties response");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (msg->len != sizeof(*fs_prop)) {
|
|
pr_warn("wrong message length: %d", msg->len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
priv->fs_version = fs_prop->version_number;
|
|
priv->fs_max_open_files = fs_prop->max_open_files;
|
|
priv->fs_caps = fs_prop->fs_capabilities;
|
|
|
|
|
|
pr_debug("< rx: fs properties: version: %d, max open files: %d, caps: %x",
|
|
priv->fs_version, priv->fs_max_open_files, priv->fs_caps);
|
|
|
|
priv->state = ISOBUSFS_CLI_STATE_GET_FS_PROPERTIES_DONE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* function to handle ISOBUSFS_CM_VOLUME_STATUS_RES */
|
|
static int isobusfs_cli_rx_volume_status_res(struct isobusfs_priv *priv,
|
|
struct isobusfs_msg *msg)
|
|
{
|
|
struct isobusfs_cm_vol_stat_res *vol_status = (void *)msg->buf;
|
|
int ret = 0;
|
|
|
|
if (priv->state != ISOBUSFS_CLI_STATE_WAIT_VOLUME_STATUS) {
|
|
pr_warn("unexpected volume status response");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_debug("< rx: volume status: %x, max time before remove %d, error code %d, path name length %d, name %s",
|
|
vol_status->volume_status,
|
|
vol_status->max_time_before_removal,
|
|
vol_status->error_code,
|
|
vol_status->name_len,
|
|
vol_status->name);
|
|
|
|
priv->state = ISOBUSFS_CLI_STATE_VOLUME_STATUS_DONE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Command group: connection management */
|
|
int isobusfs_cli_rx_cg_cm(struct isobusfs_priv *priv, struct isobusfs_msg *msg)
|
|
{
|
|
int func = isobusfs_buf_to_function(msg->buf);
|
|
int ret = 0;
|
|
|
|
switch (func) {
|
|
case ISOBUSFS_CM_F_FS_STATUS:
|
|
return isobusfs_cli_rx_fs_status(priv, msg);
|
|
case ISOBUSFS_CM_GET_FS_PROPERTIES_RES:
|
|
return isobusfs_cli_rx_fs_property_res(priv, msg);
|
|
case ISOBUSFS_CM_VOLUME_STATUS_RES:
|
|
return isobusfs_cli_rx_volume_status_res(priv, msg);
|
|
default:
|
|
pr_warn("unsupported function: %i", func);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|