diff --git a/fs/v9fs/CMakeLists.txt b/fs/v9fs/CMakeLists.txt index da46982bac6..37bb48caf09 100644 --- a/fs/v9fs/CMakeLists.txt +++ b/fs/v9fs/CMakeLists.txt @@ -27,5 +27,9 @@ if(CONFIG_FS_V9FS) list(APPEND V9FS virtio_9p.c) endif() + if(CONFIG_V9FS_SOCKET_9P) + list(APPEND V9FS socket_9p.c) + endif() + target_sources(fs PRIVATE ${V9FS}) endif() diff --git a/fs/v9fs/Kconfig b/fs/v9fs/Kconfig index 3b0cba24ff0..eb4b1cb9ec0 100644 --- a/fs/v9fs/Kconfig +++ b/fs/v9fs/Kconfig @@ -21,4 +21,9 @@ config V9FS_VIRTIO_9P depends on DRIVERS_VIRTIO default n +config V9FS_SOCKET_9P + bool "Socket 9P support" + depends on NET_TCP + default n + endif diff --git a/fs/v9fs/Make.defs b/fs/v9fs/Make.defs index 838f4f62b09..80f8b7202f9 100644 --- a/fs/v9fs/Make.defs +++ b/fs/v9fs/Make.defs @@ -25,6 +25,10 @@ ifeq ($(CONFIG_FS_V9FS),y) CSRCS += client.c transport.c v9fs.c +ifeq ($(CONFIG_V9FS_SOCKET_9P),y) + CSRCS += socket_9p.c +endif + ifeq ($(CONFIG_V9FS_VIRTIO_9P),y) CSRCS += virtio_9p.c endif diff --git a/fs/v9fs/client.c b/fs/v9fs/client.c index b6823d1b834..fbcfe6be68b 100644 --- a/fs/v9fs/client.c +++ b/fs/v9fs/client.c @@ -1811,3 +1811,13 @@ int v9fs_fid_get(FAR struct v9fs_client_s *client, uint32_t fid) nxmutex_unlock(&client->lock); return 0; } + +/**************************************************************************** + * v9fs_parse_size + ****************************************************************************/ + +ssize_t v9fs_parse_size(FAR const void *buffer) +{ + FAR const struct v9fs_header_s *ptr = buffer; + return ptr->size; +} diff --git a/fs/v9fs/client.h b/fs/v9fs/client.h index 7cd81d2d85a..0ec6c014644 100644 --- a/fs/v9fs/client.h +++ b/fs/v9fs/client.h @@ -127,5 +127,6 @@ void v9fs_transport_destroy(FAR struct v9fs_transport_s *transport); void v9fs_transport_done(FAR struct v9fs_payload_s *cookie, int ret); int v9fs_fid_put(FAR struct v9fs_client_s *client, uint32_t fid); int v9fs_fid_get(FAR struct v9fs_client_s *client, uint32_t fid); +ssize_t v9fs_parse_size(FAR const void *buffer); #endif /* __FS_V9FS_CLIENT_H */ diff --git a/fs/v9fs/socket_9p.c b/fs/v9fs/socket_9p.c new file mode 100644 index 00000000000..b4e8dbb188f --- /dev/null +++ b/fs/v9fs/socket_9p.c @@ -0,0 +1,229 @@ +/**************************************************************************** + * fs/v9fs/socket_9p.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "client.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define V9FS_HEADER_OFFSET 7 +#define V9FS_DEAFULT_PORT ":563" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct socket_9p_priv_s +{ + struct v9fs_transport_s transport; + struct socket psock; + mutex_t lock; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int socket_9p_create(FAR struct v9fs_transport_s **transport, + FAR const char *args); +static int socket_9p_request(FAR struct v9fs_transport_s *transport, + FAR struct v9fs_payload_s *payload); +static void socket_9p_destroy(FAR struct v9fs_transport_s *transport); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct v9fs_transport_ops_s g_socket_9p_transport_ops = +{ + socket_9p_create, /* create */ + socket_9p_request, /* request */ + socket_9p_destroy, /* close */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: socket_9p_create + ****************************************************************************/ + +static int socket_9p_create(FAR struct v9fs_transport_s **transport, + FAR const char *args) +{ + FAR struct socket_9p_priv_s *priv; + struct sockaddr_in sin; + FAR const char *port; + FAR const char *addr; + int ret; + + /* Parse IP and port */ + + addr = strstr(args, "tag="); + if (addr == NULL) + { + return -EINVAL; + } + + addr += 4; + port = strchr(addr, ':'); + if (port == NULL) + { + /* set default port */ + + port = V9FS_DEAFULT_PORT; + } + + priv = kmm_zalloc(sizeof(struct socket_9p_priv_s)); + if (priv == NULL) + { + return -ENOMEM; + } + + ret = psock_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP, &priv->psock); + if (ret < 0) + { + kmm_free(priv); + return ret; + } + + sin.sin_family = PF_INET; + sin.sin_port = htons(atoi(port + 1)); + sin.sin_addr.s_addr = inet_addr(addr); + ret = psock_connect(&priv->psock, (FAR const struct sockaddr *)&sin, + sizeof(sin)); + if (ret < 0) + { + goto out; + } + + nxmutex_init(&priv->lock); + priv->transport.ops = &g_socket_9p_transport_ops; + *transport = &priv->transport; + return 0; + +out: + psock_close(&priv->psock); + kmm_free(priv); + return ret; +} + +/**************************************************************************** + * Name: socket_9p_request + ****************************************************************************/ + +static int socket_9p_request(FAR struct v9fs_transport_s *transport, + FAR struct v9fs_payload_s *payload) +{ + FAR struct socket_9p_priv_s *priv = + (FAR struct socket_9p_priv_s *)transport; + struct msghdr msg; + FAR char *ptr; + size_t len; + int ret; + + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_iov = payload->wiov; + msg.msg_iovlen = payload->wcount; + + nxmutex_lock(&priv->lock); + ret = psock_sendmsg(&priv->psock, &msg, 0); + if (ret < 0) + { + goto out; + } + + ptr = payload->riov[0].iov_base; + ret = psock_recvfrom(&priv->psock, ptr, V9FS_HEADER_OFFSET, + MSG_WAITALL, NULL, NULL); + if (ret < 0) + { + goto out; + } + + len = v9fs_parse_size(ptr); + len -= ret; + + if (len > 0) + { + /* There is still data left to process */ + + int index; + + /* Skip the header */ + + payload->riov[0].iov_base += V9FS_HEADER_OFFSET; + payload->riov[0].iov_len -= V9FS_HEADER_OFFSET; + + for (index = 0; index < payload->rcount; index++) + { + payload->riov[index].iov_len = + MIN(len, payload->riov[index].iov_len); + len -= payload->riov[index].iov_len; + } + + msg.msg_iov = payload->riov; + msg.msg_iovlen = payload->rcount; + + ret = psock_recvmsg(&priv->psock, &msg, MSG_WAITALL); + if (ret < 0) + { + goto out; + } + + /* Restore the header */ + + payload->riov[0].iov_base -= V9FS_HEADER_OFFSET; + payload->riov[0].iov_len += V9FS_HEADER_OFFSET; + } + + ret = 0; + +out: + nxmutex_unlock(&priv->lock); + v9fs_transport_done(payload, ret); + return 0; +} + +/**************************************************************************** + * Name: socket_9p_destroy + ****************************************************************************/ + +static void socket_9p_destroy(FAR struct v9fs_transport_s *transport) +{ + FAR struct socket_9p_priv_s *priv = + (FAR struct socket_9p_priv_s *)transport; + + psock_close(&priv->psock); + nxmutex_destroy(&priv->lock); + kmm_free(priv); +} diff --git a/fs/v9fs/transport.c b/fs/v9fs/transport.c index 339b1fe6de3..e01facfcc6c 100644 --- a/fs/v9fs/transport.c +++ b/fs/v9fs/transport.c @@ -45,11 +45,17 @@ struct v9fs_transport_ops_map_s #ifdef CONFIG_V9FS_VIRTIO_9P extern const struct v9fs_transport_ops_s g_virtio_9p_transport_ops; #endif +#ifdef CONFIG_V9FS_SOCKET_9P +extern const struct v9fs_transport_ops_s g_socket_9p_transport_ops; +#endif static const struct v9fs_transport_ops_map_s g_transport_ops_map[] = { #ifdef CONFIG_V9FS_VIRTIO_9P { "virtio", &g_virtio_9p_transport_ops }, +#endif +#ifdef CONFIG_V9FS_SOCKET_9P + { "socket", &g_socket_9p_transport_ops }, #endif { NULL, NULL}, };