]>
Commit | Line | Data |
---|---|---|
798bfe00 | 1 | /* |
b626b51a | 2 | * Copyright (C) 2016 Red Hat, Inc. |
798bfe00 FZ |
3 | * Copyright (C) 2005 Anthony Liguori <[email protected]> |
4 | * | |
5 | * Network Block Device Client Side | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; under version 2 of the License. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
d38ea87a | 20 | #include "qemu/osdep.h" |
da34e65c | 21 | #include "qapi/error.h" |
9588463e | 22 | #include "trace.h" |
798bfe00 FZ |
23 | #include "nbd-internal.h" |
24 | ||
25 | static int nbd_errno_to_system_errno(int err) | |
26 | { | |
8b34a9db | 27 | int ret; |
798bfe00 FZ |
28 | switch (err) { |
29 | case NBD_SUCCESS: | |
8b34a9db EB |
30 | ret = 0; |
31 | break; | |
798bfe00 | 32 | case NBD_EPERM: |
8b34a9db EB |
33 | ret = EPERM; |
34 | break; | |
798bfe00 | 35 | case NBD_EIO: |
8b34a9db EB |
36 | ret = EIO; |
37 | break; | |
798bfe00 | 38 | case NBD_ENOMEM: |
8b34a9db EB |
39 | ret = ENOMEM; |
40 | break; | |
798bfe00 | 41 | case NBD_ENOSPC: |
8b34a9db EB |
42 | ret = ENOSPC; |
43 | break; | |
b6f5d3b5 EB |
44 | case NBD_ESHUTDOWN: |
45 | ret = ESHUTDOWN; | |
46 | break; | |
798bfe00 | 47 | default: |
9588463e | 48 | trace_nbd_unknown_error(err); |
f3c32fce EB |
49 | /* fallthrough */ |
50 | case NBD_EINVAL: | |
8b34a9db EB |
51 | ret = EINVAL; |
52 | break; | |
798bfe00 | 53 | } |
8b34a9db | 54 | return ret; |
798bfe00 FZ |
55 | } |
56 | ||
57 | /* Definitions for opaque data types */ | |
58 | ||
59 | static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); | |
60 | ||
61 | /* That's all folks */ | |
62 | ||
63 | /* Basic flow for negotiation | |
64 | ||
65 | Server Client | |
66 | Negotiate | |
67 | ||
68 | or | |
69 | ||
70 | Server Client | |
71 | Negotiate #1 | |
72 | Option | |
73 | Negotiate #2 | |
74 | ||
75 | ---- | |
76 | ||
77 | followed by | |
78 | ||
79 | Server Client | |
80 | Request | |
81 | Response | |
82 | Request | |
83 | Response | |
84 | ... | |
85 | ... | |
86 | Request (type == 2) | |
87 | ||
88 | */ | |
89 | ||
c8a3a1b6 EB |
90 | /* Send an option request. |
91 | * | |
92 | * The request is for option @opt, with @data containing @len bytes of | |
93 | * additional payload for the request (@len may be -1 to treat @data as | |
94 | * a C string; and @data may be NULL if @len is 0). | |
95 | * Return 0 if successful, -1 with errp set if it is impossible to | |
96 | * continue. */ | |
97 | static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt, | |
98 | uint32_t len, const char *data, | |
99 | Error **errp) | |
100 | { | |
101 | nbd_option req; | |
102 | QEMU_BUILD_BUG_ON(sizeof(req) != 16); | |
103 | ||
104 | if (len == -1) { | |
105 | req.length = len = strlen(data); | |
106 | } | |
9588463e | 107 | trace_nbd_send_option_request(opt, len); |
c8a3a1b6 EB |
108 | |
109 | stq_be_p(&req.magic, NBD_OPTS_MAGIC); | |
110 | stl_be_p(&req.option, opt); | |
111 | stl_be_p(&req.length, len); | |
112 | ||
d1fdf257 | 113 | if (nbd_write(ioc, &req, sizeof(req), errp) < 0) { |
e44ed99d | 114 | error_prepend(errp, "Failed to send option request header"); |
c8a3a1b6 EB |
115 | return -1; |
116 | } | |
117 | ||
d1fdf257 | 118 | if (len && nbd_write(ioc, (char *) data, len, errp) < 0) { |
e44ed99d | 119 | error_prepend(errp, "Failed to send option request data"); |
c8a3a1b6 EB |
120 | return -1; |
121 | } | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
2cdbf413 EB |
126 | /* Send NBD_OPT_ABORT as a courtesy to let the server know that we are |
127 | * not going to attempt further negotiation. */ | |
128 | static void nbd_send_opt_abort(QIOChannel *ioc) | |
129 | { | |
130 | /* Technically, a compliant server is supposed to reply to us; but | |
131 | * older servers disconnected instead. At any rate, we're allowed | |
132 | * to disconnect without waiting for the server reply, so we don't | |
133 | * even care if the request makes it to the server, let alone | |
134 | * waiting around for whether the server replies. */ | |
135 | nbd_send_option_request(ioc, NBD_OPT_ABORT, 0, NULL, NULL); | |
136 | } | |
137 | ||
138 | ||
c8a3a1b6 EB |
139 | /* Receive the header of an option reply, which should match the given |
140 | * opt. Read through the length field, but NOT the length bytes of | |
141 | * payload. Return 0 if successful, -1 with errp set if it is | |
142 | * impossible to continue. */ | |
143 | static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, | |
144 | nbd_opt_reply *reply, Error **errp) | |
145 | { | |
146 | QEMU_BUILD_BUG_ON(sizeof(*reply) != 20); | |
d1fdf257 | 147 | if (nbd_read(ioc, reply, sizeof(*reply), errp) < 0) { |
e44ed99d | 148 | error_prepend(errp, "failed to read option reply"); |
2cdbf413 | 149 | nbd_send_opt_abort(ioc); |
c8a3a1b6 EB |
150 | return -1; |
151 | } | |
152 | be64_to_cpus(&reply->magic); | |
153 | be32_to_cpus(&reply->option); | |
154 | be32_to_cpus(&reply->type); | |
155 | be32_to_cpus(&reply->length); | |
156 | ||
9588463e | 157 | trace_nbd_receive_option_reply(reply->option, reply->type, reply->length); |
9344e5f5 | 158 | |
c8a3a1b6 EB |
159 | if (reply->magic != NBD_REP_MAGIC) { |
160 | error_setg(errp, "Unexpected option reply magic"); | |
2cdbf413 | 161 | nbd_send_opt_abort(ioc); |
c8a3a1b6 EB |
162 | return -1; |
163 | } | |
164 | if (reply->option != opt) { | |
165 | error_setg(errp, "Unexpected option type %x expected %x", | |
166 | reply->option, opt); | |
2cdbf413 | 167 | nbd_send_opt_abort(ioc); |
c8a3a1b6 EB |
168 | return -1; |
169 | } | |
170 | return 0; | |
171 | } | |
172 | ||
173 | /* If reply represents success, return 1 without further action. | |
174 | * If reply represents an error, consume the optional payload of | |
175 | * the packet on ioc. Then return 0 for unsupported (so the client | |
176 | * can fall back to other approaches), or -1 with errp set for other | |
177 | * errors. | |
6ff58164 | 178 | */ |
c8a3a1b6 | 179 | static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply, |
6ff58164 | 180 | Error **errp) |
9344e5f5 | 181 | { |
6ff58164 AB |
182 | char *msg = NULL; |
183 | int result = -1; | |
184 | ||
c8a3a1b6 | 185 | if (!(reply->type & (1 << 31))) { |
6ff58164 AB |
186 | return 1; |
187 | } | |
188 | ||
c8a3a1b6 EB |
189 | if (reply->length) { |
190 | if (reply->length > NBD_MAX_BUFFER_SIZE) { | |
6ff58164 AB |
191 | error_setg(errp, "server's error message is too long"); |
192 | goto cleanup; | |
193 | } | |
c8a3a1b6 | 194 | msg = g_malloc(reply->length + 1); |
d1fdf257 | 195 | if (nbd_read(ioc, msg, reply->length, errp) < 0) { |
e44ed99d | 196 | error_prepend(errp, "failed to read option error message"); |
6ff58164 AB |
197 | goto cleanup; |
198 | } | |
c8a3a1b6 | 199 | msg[reply->length] = '\0'; |
9344e5f5 DB |
200 | } |
201 | ||
c8a3a1b6 | 202 | switch (reply->type) { |
9344e5f5 | 203 | case NBD_REP_ERR_UNSUP: |
9588463e | 204 | trace_nbd_reply_err_unsup(reply->option); |
6ff58164 AB |
205 | result = 0; |
206 | goto cleanup; | |
9344e5f5 | 207 | |
f95910fe | 208 | case NBD_REP_ERR_POLICY: |
c8a3a1b6 EB |
209 | error_setg(errp, "Denied by server for option %" PRIx32, |
210 | reply->option); | |
f95910fe DB |
211 | break; |
212 | ||
9344e5f5 | 213 | case NBD_REP_ERR_INVALID: |
c8a3a1b6 EB |
214 | error_setg(errp, "Invalid data length for option %" PRIx32, |
215 | reply->option); | |
9344e5f5 DB |
216 | break; |
217 | ||
b6f5d3b5 EB |
218 | case NBD_REP_ERR_PLATFORM: |
219 | error_setg(errp, "Server lacks support for option %" PRIx32, | |
220 | reply->option); | |
221 | break; | |
222 | ||
f95910fe | 223 | case NBD_REP_ERR_TLS_REQD: |
2cb34749 | 224 | error_setg(errp, "TLS negotiation required before option %" PRIx32, |
c8a3a1b6 | 225 | reply->option); |
f95910fe DB |
226 | break; |
227 | ||
b6f5d3b5 EB |
228 | case NBD_REP_ERR_SHUTDOWN: |
229 | error_setg(errp, "Server shutting down before option %" PRIx32, | |
230 | reply->option); | |
231 | break; | |
232 | ||
9344e5f5 | 233 | default: |
2cb34749 | 234 | error_setg(errp, "Unknown error code when asking for option %" PRIx32, |
c8a3a1b6 | 235 | reply->option); |
9344e5f5 DB |
236 | break; |
237 | } | |
238 | ||
6ff58164 AB |
239 | if (msg) { |
240 | error_append_hint(errp, "%s\n", msg); | |
241 | } | |
242 | ||
243 | cleanup: | |
244 | g_free(msg); | |
2cdbf413 EB |
245 | if (result < 0) { |
246 | nbd_send_opt_abort(ioc); | |
247 | } | |
6ff58164 | 248 | return result; |
9344e5f5 DB |
249 | } |
250 | ||
75368aab EB |
251 | /* Process another portion of the NBD_OPT_LIST reply. Set *@match if |
252 | * the current reply matches @want or if the server does not support | |
253 | * NBD_OPT_LIST, otherwise leave @match alone. Return 0 if iteration | |
254 | * is complete, positive if more replies are expected, or negative | |
255 | * with @errp set if an unrecoverable error occurred. */ | |
256 | static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, | |
257 | Error **errp) | |
9344e5f5 | 258 | { |
c8a3a1b6 | 259 | nbd_opt_reply reply; |
9344e5f5 DB |
260 | uint32_t len; |
261 | uint32_t namelen; | |
75368aab | 262 | char name[NBD_MAX_NAME_SIZE + 1]; |
6ff58164 | 263 | int error; |
9344e5f5 | 264 | |
c8a3a1b6 | 265 | if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) { |
9344e5f5 DB |
266 | return -1; |
267 | } | |
c8a3a1b6 | 268 | error = nbd_handle_reply_err(ioc, &reply, errp); |
6ff58164 | 269 | if (error <= 0) { |
75368aab EB |
270 | /* The server did not support NBD_OPT_LIST, so set *match on |
271 | * the assumption that any name will be accepted. */ | |
272 | *match = true; | |
6ff58164 | 273 | return error; |
9344e5f5 | 274 | } |
c8a3a1b6 | 275 | len = reply.length; |
9344e5f5 | 276 | |
c8a3a1b6 | 277 | if (reply.type == NBD_REP_ACK) { |
9344e5f5 DB |
278 | if (len != 0) { |
279 | error_setg(errp, "length too long for option end"); | |
2cdbf413 | 280 | nbd_send_opt_abort(ioc); |
9344e5f5 DB |
281 | return -1; |
282 | } | |
75368aab EB |
283 | return 0; |
284 | } else if (reply.type != NBD_REP_SERVER) { | |
285 | error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x", | |
286 | reply.type, NBD_REP_SERVER); | |
287 | nbd_send_opt_abort(ioc); | |
288 | return -1; | |
289 | } | |
9344e5f5 | 290 | |
75368aab EB |
291 | if (len < sizeof(namelen) || len > NBD_MAX_BUFFER_SIZE) { |
292 | error_setg(errp, "incorrect option length %" PRIu32, len); | |
293 | nbd_send_opt_abort(ioc); | |
294 | return -1; | |
295 | } | |
d1fdf257 | 296 | if (nbd_read(ioc, &namelen, sizeof(namelen), errp) < 0) { |
e44ed99d | 297 | error_prepend(errp, "failed to read option name length"); |
75368aab EB |
298 | nbd_send_opt_abort(ioc); |
299 | return -1; | |
300 | } | |
301 | namelen = be32_to_cpu(namelen); | |
302 | len -= sizeof(namelen); | |
303 | if (len < namelen) { | |
304 | error_setg(errp, "incorrect option name length"); | |
305 | nbd_send_opt_abort(ioc); | |
306 | return -1; | |
307 | } | |
308 | if (namelen != strlen(want)) { | |
d1fdf257 | 309 | if (nbd_drop(ioc, len, errp) < 0) { |
e44ed99d | 310 | error_prepend(errp, "failed to skip export name with wrong length"); |
7d3123e1 EB |
311 | nbd_send_opt_abort(ioc); |
312 | return -1; | |
200650d4 | 313 | } |
75368aab EB |
314 | return 1; |
315 | } | |
316 | ||
317 | assert(namelen < sizeof(name)); | |
d1fdf257 | 318 | if (nbd_read(ioc, name, namelen, errp) < 0) { |
e44ed99d | 319 | error_prepend(errp, "failed to read export name"); |
75368aab EB |
320 | nbd_send_opt_abort(ioc); |
321 | return -1; | |
322 | } | |
323 | name[namelen] = '\0'; | |
324 | len -= namelen; | |
d1fdf257 | 325 | if (nbd_drop(ioc, len, errp) < 0) { |
e44ed99d | 326 | error_prepend(errp, "failed to read export description"); |
2cdbf413 | 327 | nbd_send_opt_abort(ioc); |
9344e5f5 DB |
328 | return -1; |
329 | } | |
75368aab EB |
330 | if (!strcmp(name, want)) { |
331 | *match = true; | |
332 | } | |
9344e5f5 DB |
333 | return 1; |
334 | } | |
335 | ||
336 | ||
75368aab | 337 | /* Return -1 on failure, 0 if wantname is an available export. */ |
9344e5f5 DB |
338 | static int nbd_receive_query_exports(QIOChannel *ioc, |
339 | const char *wantname, | |
340 | Error **errp) | |
341 | { | |
9344e5f5 DB |
342 | bool foundExport = false; |
343 | ||
9588463e | 344 | trace_nbd_receive_query_exports_start(wantname); |
c8a3a1b6 | 345 | if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) { |
9344e5f5 DB |
346 | return -1; |
347 | } | |
348 | ||
9344e5f5 | 349 | while (1) { |
75368aab | 350 | int ret = nbd_receive_list(ioc, wantname, &foundExport, errp); |
9344e5f5 DB |
351 | |
352 | if (ret < 0) { | |
75368aab | 353 | /* Server gave unexpected reply */ |
9344e5f5 | 354 | return -1; |
75368aab EB |
355 | } else if (ret == 0) { |
356 | /* Done iterating. */ | |
357 | if (!foundExport) { | |
358 | error_setg(errp, "No export with name '%s' available", | |
359 | wantname); | |
360 | nbd_send_opt_abort(ioc); | |
361 | return -1; | |
362 | } | |
9588463e | 363 | trace_nbd_receive_query_exports_success(wantname); |
75368aab | 364 | return 0; |
9344e5f5 | 365 | } |
9344e5f5 | 366 | } |
9344e5f5 DB |
367 | } |
368 | ||
f95910fe DB |
369 | static QIOChannel *nbd_receive_starttls(QIOChannel *ioc, |
370 | QCryptoTLSCreds *tlscreds, | |
371 | const char *hostname, Error **errp) | |
372 | { | |
c8a3a1b6 | 373 | nbd_opt_reply reply; |
f95910fe DB |
374 | QIOChannelTLS *tioc; |
375 | struct NBDTLSHandshakeData data = { 0 }; | |
376 | ||
9588463e | 377 | trace_nbd_receive_starttls_request(); |
c8a3a1b6 | 378 | if (nbd_send_option_request(ioc, NBD_OPT_STARTTLS, 0, NULL, errp) < 0) { |
f95910fe DB |
379 | return NULL; |
380 | } | |
381 | ||
9588463e | 382 | trace_nbd_receive_starttls_reply(); |
c8a3a1b6 | 383 | if (nbd_receive_option_reply(ioc, NBD_OPT_STARTTLS, &reply, errp) < 0) { |
f95910fe DB |
384 | return NULL; |
385 | } | |
c8a3a1b6 EB |
386 | |
387 | if (reply.type != NBD_REP_ACK) { | |
2cb34749 | 388 | error_setg(errp, "Server rejected request to start TLS %" PRIx32, |
c8a3a1b6 | 389 | reply.type); |
2cdbf413 | 390 | nbd_send_opt_abort(ioc); |
f95910fe DB |
391 | return NULL; |
392 | } | |
393 | ||
c8a3a1b6 | 394 | if (reply.length != 0) { |
2cb34749 | 395 | error_setg(errp, "Start TLS response was not zero %" PRIu32, |
c8a3a1b6 | 396 | reply.length); |
2cdbf413 | 397 | nbd_send_opt_abort(ioc); |
f95910fe DB |
398 | return NULL; |
399 | } | |
400 | ||
9588463e | 401 | trace_nbd_receive_starttls_new_client(); |
f95910fe DB |
402 | tioc = qio_channel_tls_new_client(ioc, tlscreds, hostname, errp); |
403 | if (!tioc) { | |
404 | return NULL; | |
405 | } | |
0d73f725 | 406 | qio_channel_set_name(QIO_CHANNEL(tioc), "nbd-client-tls"); |
f95910fe | 407 | data.loop = g_main_loop_new(g_main_context_default(), FALSE); |
9588463e | 408 | trace_nbd_receive_starttls_tls_handshake(); |
f95910fe DB |
409 | qio_channel_tls_handshake(tioc, |
410 | nbd_tls_handshake, | |
411 | &data, | |
412 | NULL); | |
413 | ||
414 | if (!data.complete) { | |
415 | g_main_loop_run(data.loop); | |
416 | } | |
417 | g_main_loop_unref(data.loop); | |
418 | if (data.error) { | |
419 | error_propagate(errp, data.error); | |
420 | object_unref(OBJECT(tioc)); | |
421 | return NULL; | |
422 | } | |
423 | ||
424 | return QIO_CHANNEL(tioc); | |
425 | } | |
426 | ||
427 | ||
7423f417 | 428 | int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, |
f95910fe DB |
429 | QCryptoTLSCreds *tlscreds, const char *hostname, |
430 | QIOChannel **outioc, | |
798bfe00 FZ |
431 | off_t *size, Error **errp) |
432 | { | |
433 | char buf[256]; | |
434 | uint64_t magic, s; | |
798bfe00 | 435 | int rc; |
c203c59a | 436 | bool zeroes = true; |
798bfe00 | 437 | |
9588463e | 438 | trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : "<null>"); |
798bfe00 FZ |
439 | |
440 | rc = -EINVAL; | |
441 | ||
f95910fe DB |
442 | if (outioc) { |
443 | *outioc = NULL; | |
444 | } | |
445 | if (tlscreds && !outioc) { | |
446 | error_setg(errp, "Output I/O channel required for TLS"); | |
447 | goto fail; | |
448 | } | |
449 | ||
d1fdf257 | 450 | if (nbd_read(ioc, buf, 8, errp) < 0) { |
e44ed99d | 451 | error_prepend(errp, "Failed to read data"); |
798bfe00 FZ |
452 | goto fail; |
453 | } | |
454 | ||
455 | buf[8] = '\0'; | |
456 | if (strlen(buf) == 0) { | |
457 | error_setg(errp, "Server connection closed unexpectedly"); | |
458 | goto fail; | |
459 | } | |
460 | ||
458d7a69 | 461 | magic = ldq_be_p(buf); |
9588463e | 462 | trace_nbd_receive_negotiate_magic(magic); |
798bfe00 FZ |
463 | |
464 | if (memcmp(buf, "NBDMAGIC", 8) != 0) { | |
465 | error_setg(errp, "Invalid magic received"); | |
466 | goto fail; | |
467 | } | |
468 | ||
d1fdf257 | 469 | if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { |
e44ed99d | 470 | error_prepend(errp, "Failed to read magic"); |
798bfe00 FZ |
471 | goto fail; |
472 | } | |
473 | magic = be64_to_cpu(magic); | |
9588463e | 474 | trace_nbd_receive_negotiate_magic(magic); |
798bfe00 | 475 | |
f72d705f | 476 | if (magic == NBD_OPTS_MAGIC) { |
e2a9d9a3 | 477 | uint32_t clientflags = 0; |
e2a9d9a3 | 478 | uint16_t globalflags; |
9344e5f5 | 479 | bool fixedNewStyle = false; |
798bfe00 | 480 | |
d1fdf257 | 481 | if (nbd_read(ioc, &globalflags, sizeof(globalflags), errp) < 0) { |
e44ed99d | 482 | error_prepend(errp, "Failed to read server flags"); |
798bfe00 FZ |
483 | goto fail; |
484 | } | |
9344e5f5 | 485 | globalflags = be16_to_cpu(globalflags); |
9588463e | 486 | trace_nbd_receive_negotiate_server_flags(globalflags); |
e2a9d9a3 | 487 | if (globalflags & NBD_FLAG_FIXED_NEWSTYLE) { |
9344e5f5 | 488 | fixedNewStyle = true; |
e2a9d9a3 DB |
489 | clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE; |
490 | } | |
c203c59a EB |
491 | if (globalflags & NBD_FLAG_NO_ZEROES) { |
492 | zeroes = false; | |
c203c59a EB |
493 | clientflags |= NBD_FLAG_C_NO_ZEROES; |
494 | } | |
e2a9d9a3 | 495 | /* client requested flags */ |
9344e5f5 | 496 | clientflags = cpu_to_be32(clientflags); |
d1fdf257 | 497 | if (nbd_write(ioc, &clientflags, sizeof(clientflags), errp) < 0) { |
e44ed99d | 498 | error_prepend(errp, "Failed to send clientflags field"); |
798bfe00 FZ |
499 | goto fail; |
500 | } | |
f95910fe DB |
501 | if (tlscreds) { |
502 | if (fixedNewStyle) { | |
503 | *outioc = nbd_receive_starttls(ioc, tlscreds, hostname, errp); | |
504 | if (!*outioc) { | |
505 | goto fail; | |
506 | } | |
507 | ioc = *outioc; | |
508 | } else { | |
509 | error_setg(errp, "Server does not support STARTTLS"); | |
510 | goto fail; | |
511 | } | |
512 | } | |
f72d705f | 513 | if (!name) { |
9588463e | 514 | trace_nbd_receive_negotiate_default_name(); |
69b49502 | 515 | name = ""; |
f72d705f | 516 | } |
9344e5f5 DB |
517 | if (fixedNewStyle) { |
518 | /* Check our desired export is present in the | |
519 | * server export list. Since NBD_OPT_EXPORT_NAME | |
520 | * cannot return an error message, running this | |
521 | * query gives us good error reporting if the | |
522 | * server required TLS | |
523 | */ | |
524 | if (nbd_receive_query_exports(ioc, name, errp) < 0) { | |
525 | goto fail; | |
526 | } | |
527 | } | |
c8a3a1b6 EB |
528 | /* write the export name request */ |
529 | if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, name, | |
530 | errp) < 0) { | |
798bfe00 FZ |
531 | goto fail; |
532 | } | |
f72d705f | 533 | |
c8a3a1b6 | 534 | /* Read the response */ |
d1fdf257 | 535 | if (nbd_read(ioc, &s, sizeof(s), errp) < 0) { |
e44ed99d | 536 | error_prepend(errp, "Failed to read export length"); |
798bfe00 FZ |
537 | goto fail; |
538 | } | |
f72d705f | 539 | *size = be64_to_cpu(s); |
798bfe00 | 540 | |
d1fdf257 | 541 | if (nbd_read(ioc, flags, sizeof(*flags), errp) < 0) { |
e44ed99d | 542 | error_prepend(errp, "Failed to read export flags"); |
f72d705f DB |
543 | goto fail; |
544 | } | |
7423f417 | 545 | be16_to_cpus(flags); |
f72d705f | 546 | } else if (magic == NBD_CLIENT_MAGIC) { |
7423f417 EB |
547 | uint32_t oldflags; |
548 | ||
f72d705f DB |
549 | if (name) { |
550 | error_setg(errp, "Server does not support export names"); | |
551 | goto fail; | |
552 | } | |
f95910fe DB |
553 | if (tlscreds) { |
554 | error_setg(errp, "Server does not support STARTTLS"); | |
555 | goto fail; | |
556 | } | |
f72d705f | 557 | |
d1fdf257 | 558 | if (nbd_read(ioc, &s, sizeof(s), errp) < 0) { |
e44ed99d | 559 | error_prepend(errp, "Failed to read export length"); |
f72d705f DB |
560 | goto fail; |
561 | } | |
562 | *size = be64_to_cpu(s); | |
798bfe00 | 563 | |
d1fdf257 | 564 | if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { |
e44ed99d | 565 | error_prepend(errp, "Failed to read export flags"); |
798bfe00 FZ |
566 | goto fail; |
567 | } | |
7423f417 EB |
568 | be32_to_cpus(&oldflags); |
569 | if (oldflags & ~0xffff) { | |
570 | error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); | |
571 | goto fail; | |
572 | } | |
573 | *flags = oldflags; | |
798bfe00 | 574 | } else { |
f72d705f DB |
575 | error_setg(errp, "Bad magic received"); |
576 | goto fail; | |
798bfe00 | 577 | } |
f72d705f | 578 | |
9588463e | 579 | trace_nbd_receive_negotiate_size_flags(*size, *flags); |
d1fdf257 | 580 | if (zeroes && nbd_drop(ioc, 124, errp) < 0) { |
e44ed99d | 581 | error_prepend(errp, "Failed to read reserved block"); |
798bfe00 FZ |
582 | goto fail; |
583 | } | |
584 | rc = 0; | |
585 | ||
586 | fail: | |
587 | return rc; | |
588 | } | |
589 | ||
590 | #ifdef __linux__ | |
be41c100 VSO |
591 | int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size, |
592 | Error **errp) | |
798bfe00 | 593 | { |
f57e2416 EB |
594 | unsigned long sectors = size / BDRV_SECTOR_SIZE; |
595 | if (size / BDRV_SECTOR_SIZE != sectors) { | |
be41c100 VSO |
596 | error_setg(errp, "Export size %lld too large for 32-bit kernel", |
597 | (long long) size); | |
f57e2416 EB |
598 | return -E2BIG; |
599 | } | |
600 | ||
9588463e | 601 | trace_nbd_init_set_socket(); |
798bfe00 | 602 | |
f57e2416 | 603 | if (ioctl(fd, NBD_SET_SOCK, (unsigned long) sioc->fd) < 0) { |
798bfe00 | 604 | int serrno = errno; |
be41c100 | 605 | error_setg(errp, "Failed to set NBD socket"); |
798bfe00 FZ |
606 | return -serrno; |
607 | } | |
608 | ||
9588463e | 609 | trace_nbd_init_set_block_size(BDRV_SECTOR_SIZE); |
798bfe00 | 610 | |
f57e2416 | 611 | if (ioctl(fd, NBD_SET_BLKSIZE, (unsigned long)BDRV_SECTOR_SIZE) < 0) { |
798bfe00 | 612 | int serrno = errno; |
be41c100 | 613 | error_setg(errp, "Failed setting NBD block size"); |
798bfe00 FZ |
614 | return -serrno; |
615 | } | |
616 | ||
9588463e | 617 | trace_nbd_init_set_size(sectors); |
f57e2416 | 618 | if (size % BDRV_SECTOR_SIZE) { |
9588463e | 619 | trace_nbd_init_trailing_bytes(size % BDRV_SECTOR_SIZE); |
f57e2416 | 620 | } |
798bfe00 | 621 | |
f57e2416 | 622 | if (ioctl(fd, NBD_SET_SIZE_BLOCKS, sectors) < 0) { |
798bfe00 | 623 | int serrno = errno; |
be41c100 | 624 | error_setg(errp, "Failed setting size (in blocks)"); |
798bfe00 FZ |
625 | return -serrno; |
626 | } | |
627 | ||
f57e2416 | 628 | if (ioctl(fd, NBD_SET_FLAGS, (unsigned long) flags) < 0) { |
798bfe00 FZ |
629 | if (errno == ENOTTY) { |
630 | int read_only = (flags & NBD_FLAG_READ_ONLY) != 0; | |
9588463e | 631 | trace_nbd_init_set_readonly(); |
798bfe00 FZ |
632 | |
633 | if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) { | |
634 | int serrno = errno; | |
be41c100 | 635 | error_setg(errp, "Failed setting read-only attribute"); |
798bfe00 FZ |
636 | return -serrno; |
637 | } | |
638 | } else { | |
639 | int serrno = errno; | |
be41c100 | 640 | error_setg(errp, "Failed setting flags"); |
798bfe00 FZ |
641 | return -serrno; |
642 | } | |
643 | } | |
644 | ||
9588463e | 645 | trace_nbd_init_finish(); |
798bfe00 FZ |
646 | |
647 | return 0; | |
648 | } | |
649 | ||
650 | int nbd_client(int fd) | |
651 | { | |
652 | int ret; | |
653 | int serrno; | |
654 | ||
9588463e | 655 | trace_nbd_client_loop(); |
798bfe00 FZ |
656 | |
657 | ret = ioctl(fd, NBD_DO_IT); | |
658 | if (ret < 0 && errno == EPIPE) { | |
659 | /* NBD_DO_IT normally returns EPIPE when someone has disconnected | |
660 | * the socket via NBD_DISCONNECT. We do not want to return 1 in | |
661 | * that case. | |
662 | */ | |
663 | ret = 0; | |
664 | } | |
665 | serrno = errno; | |
666 | ||
9588463e | 667 | trace_nbd_client_loop_ret(ret, strerror(serrno)); |
798bfe00 | 668 | |
9588463e | 669 | trace_nbd_client_clear_queue(); |
798bfe00 FZ |
670 | ioctl(fd, NBD_CLEAR_QUE); |
671 | ||
9588463e | 672 | trace_nbd_client_clear_socket(); |
798bfe00 FZ |
673 | ioctl(fd, NBD_CLEAR_SOCK); |
674 | ||
675 | errno = serrno; | |
676 | return ret; | |
677 | } | |
98494e3b EB |
678 | |
679 | int nbd_disconnect(int fd) | |
680 | { | |
681 | ioctl(fd, NBD_CLEAR_QUE); | |
682 | ioctl(fd, NBD_DISCONNECT); | |
683 | ioctl(fd, NBD_CLEAR_SOCK); | |
684 | return 0; | |
685 | } | |
686 | ||
798bfe00 | 687 | #else |
be41c100 VSO |
688 | int nbd_init(int fd, QIOChannelSocket *ioc, uint16_t flags, off_t size, |
689 | Error **errp) | |
798bfe00 | 690 | { |
be41c100 | 691 | error_setg(errp, "nbd_init is only supported on Linux"); |
798bfe00 FZ |
692 | return -ENOTSUP; |
693 | } | |
694 | ||
695 | int nbd_client(int fd) | |
696 | { | |
697 | return -ENOTSUP; | |
698 | } | |
98494e3b EB |
699 | int nbd_disconnect(int fd) |
700 | { | |
701 | return -ENOTSUP; | |
702 | } | |
798bfe00 FZ |
703 | #endif |
704 | ||
ed2dd912 | 705 | ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request) |
798bfe00 FZ |
706 | { |
707 | uint8_t buf[NBD_REQUEST_SIZE]; | |
798bfe00 | 708 | |
9588463e VSO |
709 | trace_nbd_send_request(request->from, request->len, request->handle, |
710 | request->flags, request->type); | |
7548fe31 | 711 | |
f6be6720 | 712 | stl_be_p(buf, NBD_REQUEST_MAGIC); |
b626b51a EB |
713 | stw_be_p(buf + 4, request->flags); |
714 | stw_be_p(buf + 6, request->type); | |
f6be6720 PM |
715 | stq_be_p(buf + 8, request->handle); |
716 | stq_be_p(buf + 16, request->from); | |
717 | stl_be_p(buf + 24, request->len); | |
798bfe00 | 718 | |
d1fdf257 | 719 | return nbd_write(ioc, buf, sizeof(buf), NULL); |
798bfe00 FZ |
720 | } |
721 | ||
be41c100 | 722 | ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) |
798bfe00 FZ |
723 | { |
724 | uint8_t buf[NBD_REPLY_SIZE]; | |
725 | uint32_t magic; | |
726 | ssize_t ret; | |
727 | ||
d1fdf257 | 728 | ret = nbd_read_eof(ioc, buf, sizeof(buf), errp); |
ff82911c | 729 | if (ret <= 0) { |
798bfe00 FZ |
730 | return ret; |
731 | } | |
732 | ||
733 | if (ret != sizeof(buf)) { | |
be41c100 | 734 | error_setg(errp, "read failed"); |
798bfe00 FZ |
735 | return -EINVAL; |
736 | } | |
737 | ||
738 | /* Reply | |
739 | [ 0 .. 3] magic (NBD_REPLY_MAGIC) | |
740 | [ 4 .. 7] error (0 == no error) | |
741 | [ 7 .. 15] handle | |
742 | */ | |
743 | ||
773dce3c PM |
744 | magic = ldl_be_p(buf); |
745 | reply->error = ldl_be_p(buf + 4); | |
746 | reply->handle = ldq_be_p(buf + 8); | |
798bfe00 FZ |
747 | |
748 | reply->error = nbd_errno_to_system_errno(reply->error); | |
749 | ||
b6f5d3b5 EB |
750 | if (reply->error == ESHUTDOWN) { |
751 | /* This works even on mingw which lacks a native ESHUTDOWN */ | |
be41c100 | 752 | error_setg(errp, "server shutting down"); |
b6f5d3b5 EB |
753 | return -EINVAL; |
754 | } | |
9588463e | 755 | trace_nbd_receive_reply(magic, reply->error, reply->handle); |
798bfe00 FZ |
756 | |
757 | if (magic != NBD_REPLY_MAGIC) { | |
be41c100 | 758 | error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic); |
798bfe00 FZ |
759 | return -EINVAL; |
760 | } | |
a12a712a | 761 | return sizeof(buf); |
798bfe00 FZ |
762 | } |
763 |