--- /dev/null
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Ralph Boehme 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/util/blocking.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/debug.h"
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/smb_direct_daemon.h"
+#include "librpc/gen_ndr/ndr_smb_direct_daemon.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/util/tstream.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/msghdr.h"
+#include "lib/util/sys_rw_data.h"
+#include "smb_direct.h"
+#include "smb_direct_client.h"
+#include "smb_direct_util.h"
+
+struct smb_direct_socket {
+ int fd;
+ bool listening;
+};
+
+struct smb_direct_interface *smb_direct_get_interfaces(
+ struct smb_direct_socket *socket)
+{
+ return NULL;
+}
+
+static int smb_direct_socket_destructor(struct smb_direct_socket *s)
+{
+ if (s->fd != -1) {
+ close(s->fd);
+ s->fd = -1;
+ }
+ return 0;
+}
+
+struct smb_direct_socket *smb_direct_socket(TALLOC_CTX *mem_ctx)
+{
+ struct smb_direct_socket *s = NULL;
+ char *socket_path = NULL;
+ union {
+ struct sockaddr_un su;
+ struct sockaddr sa;
+ } addr;
+ int result;
+
+ s = talloc_zero(mem_ctx, struct smb_direct_socket);
+ if (s == NULL) {
+ return NULL;
+ }
+
+ *s = (struct smb_direct_socket) {
+ .fd = -1,
+ };
+
+ socket_path = smb_direct_socket_path(s);
+ if (socket_path == NULL) {
+ TALLOC_FREE(s);
+ return NULL;
+ }
+
+ ZERO_STRUCT(addr);
+ addr.su.sun_family = AF_UNIX;
+ strncpy(addr.su.sun_path, socket_path, sizeof(addr.su.sun_path) - 1);
+ TALLOC_FREE(socket_path);
+
+ s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s->fd == -1) {
+ TALLOC_FREE(s);
+ return NULL;
+ }
+
+ result = connect(s->fd, &addr.sa, sizeof(addr.su));
+ if (result != 0) {
+ TALLOC_FREE(s);
+ return NULL;
+ }
+
+ talloc_set_destructor(s, smb_direct_socket_destructor);
+
+ return s;
+}
+
+int smb_direct_socket_get_fd(struct smb_direct_socket *socket)
+{
+ return socket->fd;
+}
+
+static bool smb_direct_msg_send(struct smb_direct_socket *s,
+ struct sdd_packetB *packet)
+{
+ DATA_BLOB out_data = data_blob_null;
+ enum ndr_err_code ndr_err;
+ ssize_t nwritten;
+
+ ndr_err = ndr_push_struct_blob(
+ &out_data, s, packet,
+ (ndr_push_flags_fn_t)ndr_push_sdd_packetB);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("ndr_push_struct_blob failed\n");
+ return false;
+ }
+
+ SIVAL(&out_data.data[0], 0, out_data.length);
+
+ nwritten = write_data(s->fd, out_data.data, out_data.length);
+ if (nwritten != out_data.length) {
+ DBG_ERR("sendmsg failed nwritten [%zd] out_data.length [%zu] [%s]\n",
+ nwritten, out_data.length, strerror(errno));
+ TALLOC_FREE(out_data.data);
+ return false;
+ }
+
+ TALLOC_FREE(out_data.data);
+ return true;
+}
+
+static bool smb_direct_msg_recv(TALLOC_CTX *mem_ctx,
+ struct smb_direct_socket *s,
+ struct sdd_packetB *packet)
+{
+ uint8_t packet_buf[4];
+ ssize_t nread;
+ size_t packet_len;
+ DATA_BLOB response_data;
+ enum ndr_err_code ndr_err;
+
+ nread = read_data(s->fd, packet_buf, 4);
+ if (nread != 4) {
+ DBG_ERR("read failed nread [%zd] [%s] errno [%d]\n",
+ nread, strerror(errno), errno);
+ return false;
+ }
+
+ packet_len = IVAL(packet_buf, 0);
+ if (packet_len < 5 || packet_len > 0x1000) {
+ DBG_ERR("invalid packet length [%zu]\n", packet_len);
+ return false;
+ }
+
+ response_data.length = packet_len;
+
+ response_data.data = talloc_array(mem_ctx, uint8_t, packet_len);
+ if (response_data.data == NULL) {
+ DBG_ERR("talloc_array failed\n");
+ return false;
+ }
+
+ memcpy(response_data.data, packet_buf, 4);
+
+ nread = read_data(s->fd, response_data.data + 4, packet_len - 4);
+ if (nread != packet_len - 4) {
+ DBG_ERR("read failed nread [%zd] [%s] errno [%d]\n",
+ nread, strerror(errno), errno);
+ TALLOC_FREE(response_data.data);
+ return false;
+ }
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &response_data,
+ mem_ctx,
+ packet,
+ (ndr_pull_flags_fn_t)ndr_pull_sdd_packetB);
+
+ TALLOC_FREE(response_data.data);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("ndr_pull_struct_blob_all failed\n");
+ return false;
+ }
+
+ return true;
+}
+
+int smb_direct_bind(struct smb_direct_socket *socket,
+ struct smb_direct_interface *interfaces)
+{
+ return 0;
+}
+
+struct smb_direct_socket *smb_direct_listen(struct smb_direct_socket *socket,
+ struct sdd_listen_params *params)
+{
+ struct smb_direct_socket *listen_socket = NULL;
+ struct sdd_packetB request;
+ struct sdd_packetB *response = NULL;
+ struct sdd_packet_listen_request listen_request;
+ bool ok;
+
+ listen_socket = smb_direct_socket(socket);
+ if (listen_socket == NULL) {
+ return NULL;
+ }
+
+ listen_socket->listening = true;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(listen_request);
+
+ listen_request.params = *params;
+ request.command = SDD_LISTEN_REQUEST;
+ request.packet.listen_request = listen_request;
+
+ ok = smb_direct_msg_send(listen_socket, &request);
+ if (!ok) {
+ DBG_ERR("smb_direct_listen failed\n");
+ return false;
+ }
+
+ response = talloc_zero(listen_socket, struct sdd_packetB);
+ if (response == NULL) {
+ return false;
+ }
+
+ ok = smb_direct_msg_recv(response, listen_socket, response);
+ if (!ok) {
+ DBG_ERR("smb_direct_msg_recv failed\n");
+ TALLOC_FREE(response);
+ return false;
+ }
+
+ if (response->packet.listen_response.status != 0) {
+ DBG_ERR("smb_direct_listen returned status [%" PRIu32 "]\n",
+ response->packet.listen_response.status);
+ return NULL;
+ }
+
+ return listen_socket;
+}
+
+int smb_direct_accept(struct smb_direct_socket *socket)
+{
+ struct msghdr msg = { 0 };
+ int fd;
+ size_t num_fds;
+ size_t fdlen;
+ int result;
+
+ if (!socket->listening) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fdlen = msghdr_prep_recv_fds(&msg, NULL, 0, 1);
+
+ {
+ uint8_t buf[fdlen];
+
+ msghdr_prep_recv_fds(&msg, buf, fdlen, 1);
+
+ result = recvmsg(socket->fd, &msg, 0);
+ if (result == -1) {
+ DBG_ERR("recvmsg failed [%s]\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ num_fds = msghdr_extract_fds(&msg, &fd, 1);
+ if (num_fds != 1) {
+ DBG_ERR("msghdr_extract_fds failed\n");
+ return -1;
+ }
+
+ return fd;
+}
+
+bool smb_direct_ping(struct smb_direct_socket *s,
+ uint32_t in_data,
+ uint32_t *out_data)
+{
+ struct sdd_packetB request;
+ struct sdd_packetB *response = NULL;
+ struct sdd_packet_ping_request ping_request;
+ bool ok;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(ping_request);
+
+ ping_request.data = in_data;
+ request.command = SDD_PING_REQUEST;
+ request.packet.ping_request = ping_request;
+
+ ok = smb_direct_msg_send(s, &request);
+ if (!ok) {
+ DBG_ERR("smb_direct_ping failed\n");
+ return false;
+ }
+
+ response = talloc_zero(s, struct sdd_packetB);
+ if (response == NULL) {
+ return false;
+ }
+
+ ok = smb_direct_msg_recv(response, s, response);
+ if (!ok) {
+ DBG_ERR("smb_direct_msg_recv failed\n");
+ TALLOC_FREE(response);
+ return false;
+ }
+
+ *out_data = response->packet.ping_response.data;
+ return true;
+}
--- /dev/null
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Ralph Boehme 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "librpc/gen_ndr/smb_direct_daemon.h"
+
+struct smb_direct_socket;
+struct smb_direct_interface;
+
+/**
+ * @brief Get a list of RDMA capabable network interfaces
+ **/
+struct smb_direct_interface *smb_direct_get_interfaces(struct smb_direct_socket *socket);
+
+/**
+ * @brief Create a smb_direct_socket
+ *
+ * This prepares an abstract socket type that can be used for
+ * accepting RDMA sessions via smb_direct_bind(), smb_direct_listen()
+ * and smb_direct_accept().
+ *
+ * Additionally it provides an IPC channel for a small set RPC-like
+ * functions like smb_direct_get_interfaces().
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @return The smb_direct_socket.
+ **/
+struct smb_direct_socket *smb_direct_socket(TALLOC_CTX *mem_ctx);
+
+int smb_direct_socket_get_fd(struct smb_direct_socket *socket);
+int smb_direct_bind(struct smb_direct_socket *socket,
+ struct smb_direct_interface *interfaces);
+struct smb_direct_socket *smb_direct_listen(struct smb_direct_socket *socket,
+ struct sdd_listen_params *params);
+int smb_direct_accept(struct smb_direct_socket *socket);
+
+bool smb_direct_ping(struct smb_direct_socket *s,
+ uint32_t in_data,
+ uint32_t *out_data);