Used both for servers that are not fixed newstyle, and for servers
that don't understand NBD_OPT_GO.
---
generator/Makefile.am | 1 +
generator/generator | 39 +++++++++++
generator/states-newstyle-opt-export-name.c | 73 +++++++++++++++++++++
generator/states-newstyle-opt-go.c | 8 +--
generator/states-newstyle.c | 11 +++-
lib/internal.h | 1 +
lib/nbd-protocol.h | 7 ++
7 files changed, 133 insertions(+), 7 deletions(-)
create mode 100644 generator/states-newstyle-opt-export-name.c
diff --git a/generator/Makefile.am b/generator/Makefile.am
index 8262d7c..f4c127b 100644
--- a/generator/Makefile.am
+++ b/generator/Makefile.am
@@ -26,6 +26,7 @@ states_code = \
states-connect.c \
states-issue-command.c \
states-magic.c \
+ states-newstyle-opt-export-name.c \
states-newstyle-opt-go.c \
states-newstyle-opt-set-meta-context.c \
states-newstyle-opt-starttls.c \
diff --git a/generator/generator b/generator/generator
index 4d42185..60e4c55 100755
--- a/generator/generator
+++ b/generator/generator
@@ -327,6 +327,7 @@ and newstyle_state_machine = [
Group ("OPT_STRUCTURED_REPLY", newstyle_opt_structured_reply_state_machine);
Group ("OPT_SET_META_CONTEXT", newstyle_opt_set_meta_context_state_machine);
Group ("OPT_GO", newstyle_opt_go_state_machine);
+ Group ("OPT_EXPORT_NAME", newstyle_opt_export_name_state_machine);
]
(* Fixed newstyle NBD_OPT_STARTTLS option. *)
@@ -565,6 +566,44 @@ and newstyle_opt_go_state_machine = [
};
]
+(* Newstyle NBD_OPT_EXPORT_NAME option. *)
+and newstyle_opt_export_name_state_machine = [
+ State {
+ default_state with
+ name = "START";
+ comment = "Try to send newstyle NBD_OPT_EXPORT_NAME to end handshake";
+ external_events = [];
+ };
+
+ State {
+ default_state with
+ name = "SEND";
+ comment = "Send newstyle NBD_OPT_EXPORT_NAME to end handshake";
+ external_events = [ NotifyWrite, "" ];
+ };
+
+ State {
+ default_state with
+ name = "SEND_EXPORT";
+ comment = "Send newstyle NBD_OPT_EXPORT_NAME export name";
+ external_events = [ NotifyWrite, "" ];
+ };
+
+ State {
+ default_state with
+ name = "RECV_REPLY";
+ comment = "Receive newstyle NBD_OPT_EXPORT_NAME reply";
+ external_events = [ NotifyRead, "" ];
+ };
+
+ State {
+ default_state with
+ name = "CHECK_REPLY";
+ comment = "Check newstyle NBD_OPT_EXPORT_NAME reply";
+ external_events = [];
+ };
+]
+
(* Sending a command to the server. *)
and issue_command_state_machine = [
State {
diff --git a/generator/states-newstyle-opt-export-name.c
b/generator/states-newstyle-opt-export-name.c
new file mode 100644
index 0000000..6c6bce4
--- /dev/null
+++ b/generator/states-newstyle-opt-export-name.c
@@ -0,0 +1,73 @@
+/* nbd client library in userspace: state machine
+ * Copyright (C) 2013-2019 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* State machine for ending newstyle handshake with NBD_OPT_EXPORT_NAME. */
+
+/* STATE MACHINE */ {
+ NEWSTYLE.OPT_EXPORT_NAME.START:
+ conn->sbuf.option.version = htobe64 (NBD_NEW_VERSION);
+ conn->sbuf.option.option = htobe32 (NBD_OPT_EXPORT_NAME);
+ conn->sbuf.option.optlen = strlen (h->export_name);
+ conn->wbuf = &conn->sbuf;
+ conn->wlen = sizeof conn->sbuf.option;
+ SET_NEXT_STATE (%SEND);
+ return 0;
+
+ NEWSTYLE.OPT_EXPORT_NAME.SEND:
+ switch (send_from_wbuf (conn)) {
+ case -1: SET_NEXT_STATE (%.DEAD); return -1;
+ case 0:
+ conn->wbuf = h->export_name;
+ conn->wlen = strlen (h->export_name);
+ SET_NEXT_STATE (%SEND_EXPORT);
+ }
+ return 0;
+
+ NEWSTYLE.OPT_EXPORT_NAME.SEND_EXPORT:
+ switch (send_from_wbuf (conn)) {
+ case -1: SET_NEXT_STATE (%.DEAD); return -1;
+ case 0:
+ conn->rbuf = &conn->sbuf;
+ conn->rlen = sizeof conn->sbuf.export_name_reply;
+ if ((conn->gflags & NBD_FLAG_NO_ZEROES) != 0)
+ conn->rlen -= sizeof conn->sbuf.export_name_reply.zeroes;
+ SET_NEXT_STATE (%RECV_REPLY);
+ }
+ return 0;
+
+ NEWSTYLE.OPT_EXPORT_NAME.RECV_REPLY:
+ switch (recv_into_rbuf (conn)) {
+ case -1: SET_NEXT_STATE (%.DEAD); return -1;
+ case 0: SET_NEXT_STATE (%CHECK_REPLY);
+ }
+ return 0;
+
+ NEWSTYLE.OPT_EXPORT_NAME.CHECK_REPLY:
+ conn->h->exportsize = be64toh (conn->sbuf.export_name_reply.exportsize);
+ conn->h->eflags = be16toh (conn->sbuf.export_name_reply.eflags);
+ debug (conn->h, "exportsize: %" PRIu64 " eflags: 0x%" PRIx16,
+ conn->h->exportsize, conn->h->eflags);
+ if (conn->h->eflags == 0) {
+ SET_NEXT_STATE (%.DEAD);
+ set_error (EINVAL, "handshake: invalid eflags == 0 from server");
+ return -1;
+ }
+ SET_NEXT_STATE (%.READY);
+ return 0;
+
+} /* END STATE MACHINE */
diff --git a/generator/states-newstyle-opt-go.c b/generator/states-newstyle-opt-go.c
index 200d16f..42bae8a 100644
--- a/generator/states-newstyle-opt-go.c
+++ b/generator/states-newstyle-opt-go.c
@@ -149,10 +149,10 @@
SET_NEXT_STATE (%RECV_REPLY);
return 0;
case NBD_REP_ERR_UNSUP:
- /* XXX fall back to NBD_OPT_EXPORT_NAME */
- SET_NEXT_STATE (%.DEAD);
- set_error (0, "handshake: server does not support NBD_OPT_GO");
- return -1;
+ debug (conn->h,
+ "server is confused by NBD_OPT_GO, continuing anyway");
+ SET_NEXT_STATE (%^OPT_EXPORT_NAME.START);
+ return 0;
default:
SET_NEXT_STATE (%.DEAD);
set_error (0, "handshake: unknown reply from NBD_OPT_GO: 0x%" PRIx32,
diff --git a/generator/states-newstyle.c b/generator/states-newstyle.c
index f3a07f7..d108244 100644
--- a/generator/states-newstyle.c
+++ b/generator/states-newstyle.c
@@ -36,9 +36,11 @@
uint32_t cflags;
conn->gflags = be16toh (conn->gflags);
- if ((conn->gflags & NBD_FLAG_FIXED_NEWSTYLE) == 0) {
+ if ((conn->gflags & NBD_FLAG_FIXED_NEWSTYLE) == 0 &&
+ h->tls == 2) {
SET_NEXT_STATE (%.DEAD);
- set_error (0, "handshake: server is not a fixed newstyle NBD server");
+ set_error (ENOTSUP, "handshake: server is not fixed newstyle, "
+ "but handle TLS setting is require (2)");
return -1;
}
@@ -54,7 +56,10 @@
case -1: SET_NEXT_STATE (%.DEAD); return -1;
case 0:
/* Start sending options. */
- SET_NEXT_STATE (%OPT_STARTTLS.START);
+ if ((conn->gflags & NBD_FLAG_FIXED_NEWSTYLE) == 0)
+ SET_NEXT_STATE (%OPT_EXPORT_NAME.START);
+ else
+ SET_NEXT_STATE (%OPT_STARTTLS.START);
}
return 0;
diff --git a/lib/internal.h b/lib/internal.h
index f154a7b..852158a 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -127,6 +127,7 @@ struct nbd_connection {
} __attribute__((packed)) context;
} payload;
} __attribute__((packed)) or;
+ struct nbd_export_name_option_reply export_name_reply;
struct nbd_request request;
struct nbd_simple_reply simple_reply;
struct {
diff --git a/lib/nbd-protocol.h b/lib/nbd-protocol.h
index 398403a..4bda056 100644
--- a/lib/nbd-protocol.h
+++ b/lib/nbd-protocol.h
@@ -74,6 +74,13 @@ struct nbd_new_option {
/* option data follows */
} __attribute__((packed));
+/* Newstyle handshake OPT_EXPORT_NAME reply message. */
+struct nbd_export_name_option_reply {
+ uint64_t exportsize; /* size of export */
+ uint16_t eflags; /* per-export flags */
+ char zeroes[124]; /* optional zeroes */
+} __attribute__((packed));;
+
/* Fixed newstyle handshake reply message. */
struct nbd_fixed_new_option_reply {
uint64_t magic; /* NBD_REP_MAGIC */
--
2.20.1