Statistics
| Branch: | Revision:

root / nbd.c @ 07f35073

History | View | Annotate | Download (17.9 kB)

1 75818250 ths
/*
2 7a5ca864 bellard
 *  Copyright (C) 2005  Anthony Liguori <anthony@codemonkey.ws>
3 7a5ca864 bellard
 *
4 7a5ca864 bellard
 *  Network Block Device
5 7a5ca864 bellard
 *
6 7a5ca864 bellard
 *  This program is free software; you can redistribute it and/or modify
7 7a5ca864 bellard
 *  it under the terms of the GNU General Public License as published by
8 7a5ca864 bellard
 *  the Free Software Foundation; under version 2 of the License.
9 7a5ca864 bellard
 *
10 7a5ca864 bellard
 *  This program is distributed in the hope that it will be useful,
11 7a5ca864 bellard
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 7a5ca864 bellard
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 7a5ca864 bellard
 *  GNU General Public License for more details.
14 7a5ca864 bellard
 *
15 7a5ca864 bellard
 *  You should have received a copy of the GNU General Public License
16 8167ee88 Blue Swirl
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
17 75818250 ths
 */
18 7a5ca864 bellard
19 7a5ca864 bellard
#include "nbd.h"
20 ab359cd1 Markus Armbruster
#include "block.h"
21 7a5ca864 bellard
22 7a5ca864 bellard
#include <errno.h>
23 7a5ca864 bellard
#include <string.h>
24 03ff3ca3 aliguori
#ifndef _WIN32
25 7a5ca864 bellard
#include <sys/ioctl.h>
26 03ff3ca3 aliguori
#endif
27 5dc2eec9 Andreas Färber
#if defined(__sun__) || defined(__HAIKU__)
28 7e00eb9b aliguori
#include <sys/ioccom.h>
29 7e00eb9b aliguori
#endif
30 7a5ca864 bellard
#include <ctype.h>
31 7a5ca864 bellard
#include <inttypes.h>
32 75818250 ths
33 b90fb4b8 Paolo Bonzini
#ifdef __linux__
34 b90fb4b8 Paolo Bonzini
#include <linux/fs.h>
35 b90fb4b8 Paolo Bonzini
#endif
36 b90fb4b8 Paolo Bonzini
37 03ff3ca3 aliguori
#include "qemu_socket.h"
38 03ff3ca3 aliguori
39 03ff3ca3 aliguori
//#define DEBUG_NBD
40 03ff3ca3 aliguori
41 03ff3ca3 aliguori
#ifdef DEBUG_NBD
42 75818250 ths
#define TRACE(msg, ...) do { \
43 03ff3ca3 aliguori
    LOG(msg, ## __VA_ARGS__); \
44 75818250 ths
} while(0)
45 03ff3ca3 aliguori
#else
46 03ff3ca3 aliguori
#define TRACE(msg, ...) \
47 03ff3ca3 aliguori
    do { } while (0)
48 03ff3ca3 aliguori
#endif
49 7a5ca864 bellard
50 7a5ca864 bellard
#define LOG(msg, ...) do { \
51 7a5ca864 bellard
    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
52 7a5ca864 bellard
            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
53 7a5ca864 bellard
} while(0)
54 7a5ca864 bellard
55 7a5ca864 bellard
/* This is all part of the "official" NBD API */
56 7a5ca864 bellard
57 b2e3d87f Nick Thomas
#define NBD_REPLY_SIZE          (4 + 4 + 8)
58 7a5ca864 bellard
#define NBD_REQUEST_MAGIC       0x25609513
59 7a5ca864 bellard
#define NBD_REPLY_MAGIC         0x67446698
60 7a5ca864 bellard
61 7a5ca864 bellard
#define NBD_SET_SOCK            _IO(0xab, 0)
62 7a5ca864 bellard
#define NBD_SET_BLKSIZE         _IO(0xab, 1)
63 7a5ca864 bellard
#define NBD_SET_SIZE            _IO(0xab, 2)
64 7a5ca864 bellard
#define NBD_DO_IT               _IO(0xab, 3)
65 7a5ca864 bellard
#define NBD_CLEAR_SOCK          _IO(0xab, 4)
66 7a5ca864 bellard
#define NBD_CLEAR_QUE           _IO(0xab, 5)
67 b2e3d87f Nick Thomas
#define NBD_PRINT_DEBUG         _IO(0xab, 6)
68 b2e3d87f Nick Thomas
#define NBD_SET_SIZE_BLOCKS     _IO(0xab, 7)
69 7a5ca864 bellard
#define NBD_DISCONNECT          _IO(0xab, 8)
70 bbb74edd Paolo Bonzini
#define NBD_SET_TIMEOUT         _IO(0xab, 9)
71 bbb74edd Paolo Bonzini
#define NBD_SET_FLAGS           _IO(0xab, 10)
72 7a5ca864 bellard
73 b2e3d87f Nick Thomas
#define NBD_OPT_EXPORT_NAME     (1 << 0)
74 1d45f8b5 Laurent Vivier
75 7a5ca864 bellard
/* That's all folks */
76 7a5ca864 bellard
77 75818250 ths
#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
78 75818250 ths
#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
79 7a5ca864 bellard
80 75818250 ths
size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
81 7a5ca864 bellard
{
82 7a5ca864 bellard
    size_t offset = 0;
83 7a5ca864 bellard
84 7a5ca864 bellard
    while (offset < size) {
85 7a5ca864 bellard
        ssize_t len;
86 7a5ca864 bellard
87 7a5ca864 bellard
        if (do_read) {
88 00aa0040 Blue Swirl
            len = qemu_recv(fd, buffer + offset, size - offset, 0);
89 7a5ca864 bellard
        } else {
90 03ff3ca3 aliguori
            len = send(fd, buffer + offset, size - offset, 0);
91 7a5ca864 bellard
        }
92 7a5ca864 bellard
93 03ff3ca3 aliguori
        if (len == -1)
94 03ff3ca3 aliguori
            errno = socket_error();
95 03ff3ca3 aliguori
96 7a5ca864 bellard
        /* recoverable error */
97 75818250 ths
        if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
98 7a5ca864 bellard
            continue;
99 7a5ca864 bellard
        }
100 7a5ca864 bellard
101 7a5ca864 bellard
        /* eof */
102 7a5ca864 bellard
        if (len == 0) {
103 7a5ca864 bellard
            break;
104 7a5ca864 bellard
        }
105 7a5ca864 bellard
106 7a5ca864 bellard
        /* unrecoverable error */
107 7a5ca864 bellard
        if (len == -1) {
108 7a5ca864 bellard
            return 0;
109 7a5ca864 bellard
        }
110 7a5ca864 bellard
111 7a5ca864 bellard
        offset += len;
112 7a5ca864 bellard
    }
113 7a5ca864 bellard
114 7a5ca864 bellard
    return offset;
115 7a5ca864 bellard
}
116 7a5ca864 bellard
117 c12504ce Nick Thomas
static void combine_addr(char *buf, size_t len, const char* address,
118 c12504ce Nick Thomas
                         uint16_t port)
119 7a5ca864 bellard
{
120 c12504ce Nick Thomas
    /* If the address-part contains a colon, it's an IPv6 IP so needs [] */
121 c12504ce Nick Thomas
    if (strstr(address, ":")) {
122 c12504ce Nick Thomas
        snprintf(buf, len, "[%s]:%u", address, port);
123 c12504ce Nick Thomas
    } else {
124 c12504ce Nick Thomas
        snprintf(buf, len, "%s:%u", address, port);
125 7a5ca864 bellard
    }
126 7a5ca864 bellard
}
127 7a5ca864 bellard
128 c12504ce Nick Thomas
int tcp_socket_outgoing(const char *address, uint16_t port)
129 7a5ca864 bellard
{
130 c12504ce Nick Thomas
    char address_and_port[128];
131 c12504ce Nick Thomas
    combine_addr(address_and_port, 128, address, port);
132 c12504ce Nick Thomas
    return tcp_socket_outgoing_spec(address_and_port);
133 7a5ca864 bellard
}
134 7a5ca864 bellard
135 c12504ce Nick Thomas
int tcp_socket_outgoing_spec(const char *address_and_port)
136 cd831bd7 ths
{
137 c12504ce Nick Thomas
    return inet_connect(address_and_port, SOCK_STREAM);
138 cd831bd7 ths
}
139 cd831bd7 ths
140 c12504ce Nick Thomas
int tcp_socket_incoming(const char *address, uint16_t port)
141 cd831bd7 ths
{
142 c12504ce Nick Thomas
    char address_and_port[128];
143 c12504ce Nick Thomas
    combine_addr(address_and_port, 128, address, port);
144 c12504ce Nick Thomas
    return tcp_socket_incoming_spec(address_and_port);
145 c12504ce Nick Thomas
}
146 cd831bd7 ths
147 c12504ce Nick Thomas
int tcp_socket_incoming_spec(const char *address_and_port)
148 c12504ce Nick Thomas
{
149 c12504ce Nick Thomas
    char *ostr  = NULL;
150 c12504ce Nick Thomas
    int olen = 0;
151 c12504ce Nick Thomas
    return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0);
152 03ff3ca3 aliguori
}
153 c12504ce Nick Thomas
154 03ff3ca3 aliguori
int unix_socket_incoming(const char *path)
155 03ff3ca3 aliguori
{
156 c12504ce Nick Thomas
    char *ostr = NULL;
157 c12504ce Nick Thomas
    int olen = 0;
158 c12504ce Nick Thomas
159 c12504ce Nick Thomas
    return unix_listen(path, ostr, olen);
160 cd831bd7 ths
}
161 cd831bd7 ths
162 03ff3ca3 aliguori
int unix_socket_outgoing(const char *path)
163 03ff3ca3 aliguori
{
164 c12504ce Nick Thomas
    return unix_connect(path);
165 03ff3ca3 aliguori
}
166 cd831bd7 ths
167 7a5ca864 bellard
/* Basic flow
168 7a5ca864 bellard

169 7a5ca864 bellard
   Server         Client
170 7a5ca864 bellard

171 7a5ca864 bellard
   Negotiate
172 7a5ca864 bellard
                  Request
173 7a5ca864 bellard
   Response
174 7a5ca864 bellard
                  Request
175 7a5ca864 bellard
   Response
176 7a5ca864 bellard
                  ...
177 7a5ca864 bellard
   ...
178 7a5ca864 bellard
                  Request (type == 2)
179 7a5ca864 bellard
*/
180 7a5ca864 bellard
181 b90fb4b8 Paolo Bonzini
int nbd_negotiate(int csock, off_t size, uint32_t flags)
182 7a5ca864 bellard
{
183 b2e3d87f Nick Thomas
    char buf[8 + 8 + 8 + 128];
184 b2e3d87f Nick Thomas
185 b2e3d87f Nick Thomas
    /* Negotiate
186 b2e3d87f Nick Thomas
        [ 0 ..   7]   passwd   ("NBDMAGIC")
187 b2e3d87f Nick Thomas
        [ 8 ..  15]   magic    (0x00420281861253)
188 b2e3d87f Nick Thomas
        [16 ..  23]   size
189 b90fb4b8 Paolo Bonzini
        [24 ..  27]   flags
190 b90fb4b8 Paolo Bonzini
        [28 .. 151]   reserved (0)
191 b2e3d87f Nick Thomas
     */
192 b2e3d87f Nick Thomas
193 b2e3d87f Nick Thomas
    TRACE("Beginning negotiation.");
194 b2e3d87f Nick Thomas
    memcpy(buf, "NBDMAGIC", 8);
195 b2e3d87f Nick Thomas
    cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
196 b2e3d87f Nick Thomas
    cpu_to_be64w((uint64_t*)(buf + 16), size);
197 b90fb4b8 Paolo Bonzini
    cpu_to_be32w((uint32_t*)(buf + 24), flags | NBD_FLAG_HAS_FLAGS);
198 b90fb4b8 Paolo Bonzini
    memset(buf + 28, 0, 124);
199 b2e3d87f Nick Thomas
200 b2e3d87f Nick Thomas
    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
201 b2e3d87f Nick Thomas
        LOG("write failed");
202 b2e3d87f Nick Thomas
        errno = EINVAL;
203 b2e3d87f Nick Thomas
        return -1;
204 b2e3d87f Nick Thomas
    }
205 b2e3d87f Nick Thomas
206 07f35073 Dong Xu Wang
    TRACE("Negotiation succeeded.");
207 b2e3d87f Nick Thomas
208 b2e3d87f Nick Thomas
    return 0;
209 7a5ca864 bellard
}
210 7a5ca864 bellard
211 1d45f8b5 Laurent Vivier
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
212 1d45f8b5 Laurent Vivier
                          off_t *size, size_t *blocksize)
213 7a5ca864 bellard
{
214 b2e3d87f Nick Thomas
    char buf[256];
215 b2e3d87f Nick Thomas
    uint64_t magic, s;
216 b2e3d87f Nick Thomas
    uint16_t tmp;
217 b2e3d87f Nick Thomas
218 07f35073 Dong Xu Wang
    TRACE("Receiving negotiation.");
219 b2e3d87f Nick Thomas
220 b2e3d87f Nick Thomas
    if (read_sync(csock, buf, 8) != 8) {
221 b2e3d87f Nick Thomas
        LOG("read failed");
222 b2e3d87f Nick Thomas
        errno = EINVAL;
223 b2e3d87f Nick Thomas
        return -1;
224 b2e3d87f Nick Thomas
    }
225 b2e3d87f Nick Thomas
226 b2e3d87f Nick Thomas
    buf[8] = '\0';
227 b2e3d87f Nick Thomas
    if (strlen(buf) == 0) {
228 b2e3d87f Nick Thomas
        LOG("server connection closed");
229 b2e3d87f Nick Thomas
        errno = EINVAL;
230 b2e3d87f Nick Thomas
        return -1;
231 b2e3d87f Nick Thomas
    }
232 b2e3d87f Nick Thomas
233 b2e3d87f Nick Thomas
    TRACE("Magic is %c%c%c%c%c%c%c%c",
234 b2e3d87f Nick Thomas
          qemu_isprint(buf[0]) ? buf[0] : '.',
235 b2e3d87f Nick Thomas
          qemu_isprint(buf[1]) ? buf[1] : '.',
236 b2e3d87f Nick Thomas
          qemu_isprint(buf[2]) ? buf[2] : '.',
237 b2e3d87f Nick Thomas
          qemu_isprint(buf[3]) ? buf[3] : '.',
238 b2e3d87f Nick Thomas
          qemu_isprint(buf[4]) ? buf[4] : '.',
239 b2e3d87f Nick Thomas
          qemu_isprint(buf[5]) ? buf[5] : '.',
240 b2e3d87f Nick Thomas
          qemu_isprint(buf[6]) ? buf[6] : '.',
241 b2e3d87f Nick Thomas
          qemu_isprint(buf[7]) ? buf[7] : '.');
242 b2e3d87f Nick Thomas
243 b2e3d87f Nick Thomas
    if (memcmp(buf, "NBDMAGIC", 8) != 0) {
244 b2e3d87f Nick Thomas
        LOG("Invalid magic received");
245 b2e3d87f Nick Thomas
        errno = EINVAL;
246 b2e3d87f Nick Thomas
        return -1;
247 b2e3d87f Nick Thomas
    }
248 b2e3d87f Nick Thomas
249 b2e3d87f Nick Thomas
    if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
250 b2e3d87f Nick Thomas
        LOG("read failed");
251 b2e3d87f Nick Thomas
        errno = EINVAL;
252 b2e3d87f Nick Thomas
        return -1;
253 b2e3d87f Nick Thomas
    }
254 b2e3d87f Nick Thomas
    magic = be64_to_cpu(magic);
255 b2e3d87f Nick Thomas
    TRACE("Magic is 0x%" PRIx64, magic);
256 b2e3d87f Nick Thomas
257 b2e3d87f Nick Thomas
    if (name) {
258 b2e3d87f Nick Thomas
        uint32_t reserved = 0;
259 b2e3d87f Nick Thomas
        uint32_t opt;
260 b2e3d87f Nick Thomas
        uint32_t namesize;
261 b2e3d87f Nick Thomas
262 b2e3d87f Nick Thomas
        TRACE("Checking magic (opts_magic)");
263 b2e3d87f Nick Thomas
        if (magic != 0x49484156454F5054LL) {
264 b2e3d87f Nick Thomas
            LOG("Bad magic received");
265 b2e3d87f Nick Thomas
            errno = EINVAL;
266 b2e3d87f Nick Thomas
            return -1;
267 b2e3d87f Nick Thomas
        }
268 b2e3d87f Nick Thomas
        if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
269 b2e3d87f Nick Thomas
            LOG("flags read failed");
270 b2e3d87f Nick Thomas
            errno = EINVAL;
271 b2e3d87f Nick Thomas
            return -1;
272 b2e3d87f Nick Thomas
        }
273 b2e3d87f Nick Thomas
        *flags = be16_to_cpu(tmp) << 16;
274 b2e3d87f Nick Thomas
        /* reserved for future use */
275 b2e3d87f Nick Thomas
        if (write_sync(csock, &reserved, sizeof(reserved)) !=
276 b2e3d87f Nick Thomas
            sizeof(reserved)) {
277 b2e3d87f Nick Thomas
            LOG("write failed (reserved)");
278 b2e3d87f Nick Thomas
            errno = EINVAL;
279 b2e3d87f Nick Thomas
            return -1;
280 b2e3d87f Nick Thomas
        }
281 b2e3d87f Nick Thomas
        /* write the export name */
282 b2e3d87f Nick Thomas
        magic = cpu_to_be64(magic);
283 b2e3d87f Nick Thomas
        if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
284 b2e3d87f Nick Thomas
            LOG("write failed (magic)");
285 b2e3d87f Nick Thomas
            errno = EINVAL;
286 b2e3d87f Nick Thomas
            return -1;
287 b2e3d87f Nick Thomas
        }
288 b2e3d87f Nick Thomas
        opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
289 b2e3d87f Nick Thomas
        if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
290 b2e3d87f Nick Thomas
            LOG("write failed (opt)");
291 b2e3d87f Nick Thomas
            errno = EINVAL;
292 b2e3d87f Nick Thomas
            return -1;
293 b2e3d87f Nick Thomas
        }
294 b2e3d87f Nick Thomas
        namesize = cpu_to_be32(strlen(name));
295 b2e3d87f Nick Thomas
        if (write_sync(csock, &namesize, sizeof(namesize)) !=
296 b2e3d87f Nick Thomas
            sizeof(namesize)) {
297 b2e3d87f Nick Thomas
            LOG("write failed (namesize)");
298 b2e3d87f Nick Thomas
            errno = EINVAL;
299 b2e3d87f Nick Thomas
            return -1;
300 b2e3d87f Nick Thomas
        }
301 b2e3d87f Nick Thomas
        if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
302 b2e3d87f Nick Thomas
            LOG("write failed (name)");
303 b2e3d87f Nick Thomas
            errno = EINVAL;
304 b2e3d87f Nick Thomas
            return -1;
305 b2e3d87f Nick Thomas
        }
306 b2e3d87f Nick Thomas
    } else {
307 b2e3d87f Nick Thomas
        TRACE("Checking magic (cli_magic)");
308 b2e3d87f Nick Thomas
309 b2e3d87f Nick Thomas
        if (magic != 0x00420281861253LL) {
310 b2e3d87f Nick Thomas
            LOG("Bad magic received");
311 b2e3d87f Nick Thomas
            errno = EINVAL;
312 b2e3d87f Nick Thomas
            return -1;
313 b2e3d87f Nick Thomas
        }
314 b2e3d87f Nick Thomas
    }
315 b2e3d87f Nick Thomas
316 b2e3d87f Nick Thomas
    if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
317 b2e3d87f Nick Thomas
        LOG("read failed");
318 b2e3d87f Nick Thomas
        errno = EINVAL;
319 b2e3d87f Nick Thomas
        return -1;
320 b2e3d87f Nick Thomas
    }
321 b2e3d87f Nick Thomas
    *size = be64_to_cpu(s);
322 b2e3d87f Nick Thomas
    *blocksize = 1024;
323 b2e3d87f Nick Thomas
    TRACE("Size is %" PRIu64, *size);
324 b2e3d87f Nick Thomas
325 b2e3d87f Nick Thomas
    if (!name) {
326 b2e3d87f Nick Thomas
        if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
327 b2e3d87f Nick Thomas
            LOG("read failed (flags)");
328 b2e3d87f Nick Thomas
            errno = EINVAL;
329 b2e3d87f Nick Thomas
            return -1;
330 b2e3d87f Nick Thomas
        }
331 b2e3d87f Nick Thomas
        *flags = be32_to_cpup(flags);
332 b2e3d87f Nick Thomas
    } else {
333 b2e3d87f Nick Thomas
        if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
334 b2e3d87f Nick Thomas
            LOG("read failed (tmp)");
335 b2e3d87f Nick Thomas
            errno = EINVAL;
336 b2e3d87f Nick Thomas
            return -1;
337 b2e3d87f Nick Thomas
        }
338 b2e3d87f Nick Thomas
        *flags |= be32_to_cpu(tmp);
339 b2e3d87f Nick Thomas
    }
340 b2e3d87f Nick Thomas
    if (read_sync(csock, &buf, 124) != 124) {
341 b2e3d87f Nick Thomas
        LOG("read failed (buf)");
342 b2e3d87f Nick Thomas
        errno = EINVAL;
343 b2e3d87f Nick Thomas
        return -1;
344 b2e3d87f Nick Thomas
    }
345 cd831bd7 ths
        return 0;
346 cd831bd7 ths
}
347 7a5ca864 bellard
348 b90fb4b8 Paolo Bonzini
#ifdef __linux__
349 b90fb4b8 Paolo Bonzini
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
350 cd831bd7 ths
{
351 b2e3d87f Nick Thomas
    TRACE("Setting block size to %lu", (unsigned long)blocksize);
352 7a5ca864 bellard
353 b2e3d87f Nick Thomas
    if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
354 b2e3d87f Nick Thomas
        int serrno = errno;
355 b2e3d87f Nick Thomas
        LOG("Failed setting NBD block size");
356 b2e3d87f Nick Thomas
        errno = serrno;
357 b2e3d87f Nick Thomas
        return -1;
358 b2e3d87f Nick Thomas
    }
359 7a5ca864 bellard
360 0bfcd599 Blue Swirl
        TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
361 7a5ca864 bellard
362 b2e3d87f Nick Thomas
    if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
363 b2e3d87f Nick Thomas
        int serrno = errno;
364 b2e3d87f Nick Thomas
        LOG("Failed setting size (in blocks)");
365 b2e3d87f Nick Thomas
        errno = serrno;
366 b2e3d87f Nick Thomas
        return -1;
367 b2e3d87f Nick Thomas
    }
368 7a5ca864 bellard
369 b90fb4b8 Paolo Bonzini
    if (flags & NBD_FLAG_READ_ONLY) {
370 b90fb4b8 Paolo Bonzini
        int read_only = 1;
371 b90fb4b8 Paolo Bonzini
        TRACE("Setting readonly attribute");
372 b90fb4b8 Paolo Bonzini
373 b90fb4b8 Paolo Bonzini
        if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
374 b90fb4b8 Paolo Bonzini
            int serrno = errno;
375 b90fb4b8 Paolo Bonzini
            LOG("Failed setting read-only attribute");
376 b90fb4b8 Paolo Bonzini
            errno = serrno;
377 b90fb4b8 Paolo Bonzini
            return -1;
378 b90fb4b8 Paolo Bonzini
        }
379 b90fb4b8 Paolo Bonzini
    }
380 b90fb4b8 Paolo Bonzini
381 973b3d0a Paolo Bonzini
    if (ioctl(fd, NBD_SET_FLAGS, flags) < 0
382 973b3d0a Paolo Bonzini
        && errno != ENOTTY) {
383 973b3d0a Paolo Bonzini
        int serrno = errno;
384 973b3d0a Paolo Bonzini
        LOG("Failed setting flags");
385 973b3d0a Paolo Bonzini
        errno = serrno;
386 973b3d0a Paolo Bonzini
        return -1;
387 973b3d0a Paolo Bonzini
    }
388 973b3d0a Paolo Bonzini
389 b2e3d87f Nick Thomas
    TRACE("Clearing NBD socket");
390 7a5ca864 bellard
391 b2e3d87f Nick Thomas
    if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
392 b2e3d87f Nick Thomas
        int serrno = errno;
393 b2e3d87f Nick Thomas
        LOG("Failed clearing NBD socket");
394 b2e3d87f Nick Thomas
        errno = serrno;
395 b2e3d87f Nick Thomas
        return -1;
396 b2e3d87f Nick Thomas
    }
397 7a5ca864 bellard
398 b2e3d87f Nick Thomas
    TRACE("Setting NBD socket");
399 7a5ca864 bellard
400 b2e3d87f Nick Thomas
    if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
401 b2e3d87f Nick Thomas
        int serrno = errno;
402 b2e3d87f Nick Thomas
        LOG("Failed to set NBD socket");
403 b2e3d87f Nick Thomas
        errno = serrno;
404 b2e3d87f Nick Thomas
        return -1;
405 b2e3d87f Nick Thomas
    }
406 7a5ca864 bellard
407 b2e3d87f Nick Thomas
    TRACE("Negotiation ended");
408 7a5ca864 bellard
409 b2e3d87f Nick Thomas
    return 0;
410 7a5ca864 bellard
}
411 7a5ca864 bellard
412 7a5ca864 bellard
int nbd_disconnect(int fd)
413 7a5ca864 bellard
{
414 b2e3d87f Nick Thomas
    ioctl(fd, NBD_CLEAR_QUE);
415 b2e3d87f Nick Thomas
    ioctl(fd, NBD_DISCONNECT);
416 b2e3d87f Nick Thomas
    ioctl(fd, NBD_CLEAR_SOCK);
417 b2e3d87f Nick Thomas
    return 0;
418 7a5ca864 bellard
}
419 7a5ca864 bellard
420 0a4eb864 Jes Sorensen
int nbd_client(int fd)
421 7a5ca864 bellard
{
422 b2e3d87f Nick Thomas
    int ret;
423 b2e3d87f Nick Thomas
    int serrno;
424 7a5ca864 bellard
425 b2e3d87f Nick Thomas
    TRACE("Doing NBD loop");
426 7a5ca864 bellard
427 b2e3d87f Nick Thomas
    ret = ioctl(fd, NBD_DO_IT);
428 74624688 Paolo Bonzini
    if (ret == -1 && errno == EPIPE) {
429 74624688 Paolo Bonzini
        /* NBD_DO_IT normally returns EPIPE when someone has disconnected
430 74624688 Paolo Bonzini
         * the socket via NBD_DISCONNECT.  We do not want to return 1 in
431 74624688 Paolo Bonzini
         * that case.
432 74624688 Paolo Bonzini
         */
433 74624688 Paolo Bonzini
        ret = 0;
434 74624688 Paolo Bonzini
    }
435 b2e3d87f Nick Thomas
    serrno = errno;
436 7a5ca864 bellard
437 b2e3d87f Nick Thomas
    TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
438 7a5ca864 bellard
439 b2e3d87f Nick Thomas
    TRACE("Clearing NBD queue");
440 b2e3d87f Nick Thomas
    ioctl(fd, NBD_CLEAR_QUE);
441 7a5ca864 bellard
442 b2e3d87f Nick Thomas
    TRACE("Clearing NBD socket");
443 b2e3d87f Nick Thomas
    ioctl(fd, NBD_CLEAR_SOCK);
444 7a5ca864 bellard
445 b2e3d87f Nick Thomas
    errno = serrno;
446 b2e3d87f Nick Thomas
    return ret;
447 7a5ca864 bellard
}
448 03ff3ca3 aliguori
#else
449 8e72506e Paolo Bonzini
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
450 03ff3ca3 aliguori
{
451 03ff3ca3 aliguori
    errno = ENOTSUP;
452 03ff3ca3 aliguori
    return -1;
453 03ff3ca3 aliguori
}
454 03ff3ca3 aliguori
455 03ff3ca3 aliguori
int nbd_disconnect(int fd)
456 03ff3ca3 aliguori
{
457 03ff3ca3 aliguori
    errno = ENOTSUP;
458 03ff3ca3 aliguori
    return -1;
459 03ff3ca3 aliguori
}
460 03ff3ca3 aliguori
461 0a4eb864 Jes Sorensen
int nbd_client(int fd)
462 03ff3ca3 aliguori
{
463 03ff3ca3 aliguori
    errno = ENOTSUP;
464 03ff3ca3 aliguori
    return -1;
465 03ff3ca3 aliguori
}
466 03ff3ca3 aliguori
#endif
467 7a5ca864 bellard
468 75818250 ths
int nbd_send_request(int csock, struct nbd_request *request)
469 7a5ca864 bellard
{
470 b2e3d87f Nick Thomas
    uint8_t buf[4 + 4 + 8 + 8 + 4];
471 b2e3d87f Nick Thomas
472 b2e3d87f Nick Thomas
    cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
473 b2e3d87f Nick Thomas
    cpu_to_be32w((uint32_t*)(buf + 4), request->type);
474 b2e3d87f Nick Thomas
    cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
475 b2e3d87f Nick Thomas
    cpu_to_be64w((uint64_t*)(buf + 16), request->from);
476 b2e3d87f Nick Thomas
    cpu_to_be32w((uint32_t*)(buf + 24), request->len);
477 75818250 ths
478 b2e3d87f Nick Thomas
    TRACE("Sending request to client: "
479 b2e3d87f Nick Thomas
          "{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
480 b2e3d87f Nick Thomas
          request->from, request->len, request->handle, request->type);
481 b2e3d87f Nick Thomas
482 b2e3d87f Nick Thomas
    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
483 b2e3d87f Nick Thomas
        LOG("writing to socket failed");
484 b2e3d87f Nick Thomas
        errno = EINVAL;
485 b2e3d87f Nick Thomas
        return -1;
486 b2e3d87f Nick Thomas
    }
487 b2e3d87f Nick Thomas
    return 0;
488 b2e3d87f Nick Thomas
}
489 75818250 ths
490 75818250 ths
static int nbd_receive_request(int csock, struct nbd_request *request)
491 75818250 ths
{
492 b2e3d87f Nick Thomas
    uint8_t buf[4 + 4 + 8 + 8 + 4];
493 b2e3d87f Nick Thomas
    uint32_t magic;
494 b2e3d87f Nick Thomas
495 b2e3d87f Nick Thomas
    if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
496 b2e3d87f Nick Thomas
        LOG("read failed");
497 b2e3d87f Nick Thomas
        errno = EINVAL;
498 b2e3d87f Nick Thomas
        return -1;
499 b2e3d87f Nick Thomas
    }
500 b2e3d87f Nick Thomas
501 b2e3d87f Nick Thomas
    /* Request
502 b2e3d87f Nick Thomas
       [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
503 b2e3d87f Nick Thomas
       [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
504 b2e3d87f Nick Thomas
       [ 8 .. 15]   handle
505 b2e3d87f Nick Thomas
       [16 .. 23]   from
506 b2e3d87f Nick Thomas
       [24 .. 27]   len
507 b2e3d87f Nick Thomas
     */
508 b2e3d87f Nick Thomas
509 b2e3d87f Nick Thomas
    magic = be32_to_cpup((uint32_t*)buf);
510 b2e3d87f Nick Thomas
    request->type  = be32_to_cpup((uint32_t*)(buf + 4));
511 b2e3d87f Nick Thomas
    request->handle = be64_to_cpup((uint64_t*)(buf + 8));
512 b2e3d87f Nick Thomas
    request->from  = be64_to_cpup((uint64_t*)(buf + 16));
513 b2e3d87f Nick Thomas
    request->len   = be32_to_cpup((uint32_t*)(buf + 24));
514 b2e3d87f Nick Thomas
515 b2e3d87f Nick Thomas
    TRACE("Got request: "
516 b2e3d87f Nick Thomas
          "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
517 b2e3d87f Nick Thomas
          magic, request->type, request->from, request->len);
518 b2e3d87f Nick Thomas
519 b2e3d87f Nick Thomas
    if (magic != NBD_REQUEST_MAGIC) {
520 b2e3d87f Nick Thomas
        LOG("invalid magic (got 0x%x)", magic);
521 b2e3d87f Nick Thomas
        errno = EINVAL;
522 b2e3d87f Nick Thomas
        return -1;
523 b2e3d87f Nick Thomas
    }
524 b2e3d87f Nick Thomas
    return 0;
525 75818250 ths
}
526 75818250 ths
527 75818250 ths
int nbd_receive_reply(int csock, struct nbd_reply *reply)
528 75818250 ths
{
529 b2e3d87f Nick Thomas
    uint8_t buf[NBD_REPLY_SIZE];
530 b2e3d87f Nick Thomas
    uint32_t magic;
531 b2e3d87f Nick Thomas
532 b2e3d87f Nick Thomas
    memset(buf, 0xAA, sizeof(buf));
533 b2e3d87f Nick Thomas
534 b2e3d87f Nick Thomas
    if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
535 b2e3d87f Nick Thomas
        LOG("read failed");
536 b2e3d87f Nick Thomas
        errno = EINVAL;
537 b2e3d87f Nick Thomas
        return -1;
538 b2e3d87f Nick Thomas
    }
539 b2e3d87f Nick Thomas
540 b2e3d87f Nick Thomas
    /* Reply
541 b2e3d87f Nick Thomas
       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
542 b2e3d87f Nick Thomas
       [ 4 ..  7]    error   (0 == no error)
543 b2e3d87f Nick Thomas
       [ 7 .. 15]    handle
544 b2e3d87f Nick Thomas
     */
545 b2e3d87f Nick Thomas
546 b2e3d87f Nick Thomas
    magic = be32_to_cpup((uint32_t*)buf);
547 b2e3d87f Nick Thomas
    reply->error  = be32_to_cpup((uint32_t*)(buf + 4));
548 b2e3d87f Nick Thomas
    reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
549 b2e3d87f Nick Thomas
550 b2e3d87f Nick Thomas
    TRACE("Got reply: "
551 b2e3d87f Nick Thomas
          "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
552 b2e3d87f Nick Thomas
          magic, reply->error, reply->handle);
553 b2e3d87f Nick Thomas
554 b2e3d87f Nick Thomas
    if (magic != NBD_REPLY_MAGIC) {
555 b2e3d87f Nick Thomas
        LOG("invalid magic (got 0x%x)", magic);
556 b2e3d87f Nick Thomas
        errno = EINVAL;
557 b2e3d87f Nick Thomas
        return -1;
558 b2e3d87f Nick Thomas
    }
559 b2e3d87f Nick Thomas
    return 0;
560 75818250 ths
}
561 75818250 ths
562 75818250 ths
static int nbd_send_reply(int csock, struct nbd_reply *reply)
563 75818250 ths
{
564 b2e3d87f Nick Thomas
    uint8_t buf[4 + 4 + 8];
565 b2e3d87f Nick Thomas
566 b2e3d87f Nick Thomas
    /* Reply
567 b2e3d87f Nick Thomas
       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
568 b2e3d87f Nick Thomas
       [ 4 ..  7]    error   (0 == no error)
569 b2e3d87f Nick Thomas
       [ 7 .. 15]    handle
570 b2e3d87f Nick Thomas
     */
571 b2e3d87f Nick Thomas
    cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
572 b2e3d87f Nick Thomas
    cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
573 b2e3d87f Nick Thomas
    cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
574 b2e3d87f Nick Thomas
575 b2e3d87f Nick Thomas
    TRACE("Sending response to client");
576 b2e3d87f Nick Thomas
577 b2e3d87f Nick Thomas
    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
578 b2e3d87f Nick Thomas
        LOG("writing to socket failed");
579 b2e3d87f Nick Thomas
        errno = EINVAL;
580 b2e3d87f Nick Thomas
        return -1;
581 b2e3d87f Nick Thomas
    }
582 b2e3d87f Nick Thomas
    return 0;
583 75818250 ths
}
584 7a5ca864 bellard
585 75818250 ths
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
586 b90fb4b8 Paolo Bonzini
             off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size)
587 75818250 ths
{
588 b2e3d87f Nick Thomas
    struct nbd_request request;
589 b2e3d87f Nick Thomas
    struct nbd_reply reply;
590 b2e3d87f Nick Thomas
591 b2e3d87f Nick Thomas
    TRACE("Reading request.");
592 b2e3d87f Nick Thomas
593 b2e3d87f Nick Thomas
    if (nbd_receive_request(csock, &request) == -1)
594 b2e3d87f Nick Thomas
        return -1;
595 b2e3d87f Nick Thomas
596 b2e3d87f Nick Thomas
    if (request.len + NBD_REPLY_SIZE > data_size) {
597 b2e3d87f Nick Thomas
        LOG("len (%u) is larger than max len (%u)",
598 b2e3d87f Nick Thomas
            request.len + NBD_REPLY_SIZE, data_size);
599 b2e3d87f Nick Thomas
        errno = EINVAL;
600 b2e3d87f Nick Thomas
        return -1;
601 b2e3d87f Nick Thomas
    }
602 b2e3d87f Nick Thomas
603 b2e3d87f Nick Thomas
    if ((request.from + request.len) < request.from) {
604 b2e3d87f Nick Thomas
        LOG("integer overflow detected! "
605 b2e3d87f Nick Thomas
            "you're probably being attacked");
606 b2e3d87f Nick Thomas
        errno = EINVAL;
607 b2e3d87f Nick Thomas
        return -1;
608 b2e3d87f Nick Thomas
    }
609 b2e3d87f Nick Thomas
610 b2e3d87f Nick Thomas
    if ((request.from + request.len) > size) {
611 b2e3d87f Nick Thomas
            LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
612 b2e3d87f Nick Thomas
            ", Offset: %" PRIu64 "\n",
613 b9e82a59 blueswir1
                    request.from, request.len, (uint64_t)size, dev_offset);
614 b2e3d87f Nick Thomas
        LOG("requested operation past EOF--bad client?");
615 b2e3d87f Nick Thomas
        errno = EINVAL;
616 b2e3d87f Nick Thomas
        return -1;
617 b2e3d87f Nick Thomas
    }
618 b2e3d87f Nick Thomas
619 b2e3d87f Nick Thomas
    TRACE("Decoding type");
620 b2e3d87f Nick Thomas
621 b2e3d87f Nick Thomas
    reply.handle = request.handle;
622 b2e3d87f Nick Thomas
    reply.error = 0;
623 b2e3d87f Nick Thomas
624 b2e3d87f Nick Thomas
    switch (request.type) {
625 b2e3d87f Nick Thomas
    case NBD_CMD_READ:
626 b2e3d87f Nick Thomas
        TRACE("Request type is READ");
627 b2e3d87f Nick Thomas
628 b2e3d87f Nick Thomas
        if (bdrv_read(bs, (request.from + dev_offset) / 512,
629 b2e3d87f Nick Thomas
                  data + NBD_REPLY_SIZE,
630 b2e3d87f Nick Thomas
                  request.len / 512) == -1) {
631 b2e3d87f Nick Thomas
            LOG("reading from file failed");
632 b2e3d87f Nick Thomas
            errno = EINVAL;
633 b2e3d87f Nick Thomas
            return -1;
634 b2e3d87f Nick Thomas
        }
635 b2e3d87f Nick Thomas
        *offset += request.len;
636 b2e3d87f Nick Thomas
637 b2e3d87f Nick Thomas
        TRACE("Read %u byte(s)", request.len);
638 b2e3d87f Nick Thomas
639 b2e3d87f Nick Thomas
        /* Reply
640 b2e3d87f Nick Thomas
           [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
641 b2e3d87f Nick Thomas
           [ 4 ..  7]    error   (0 == no error)
642 b2e3d87f Nick Thomas
           [ 7 .. 15]    handle
643 b2e3d87f Nick Thomas
         */
644 b2e3d87f Nick Thomas
645 b2e3d87f Nick Thomas
        cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC);
646 b2e3d87f Nick Thomas
        cpu_to_be32w((uint32_t*)(data + 4), reply.error);
647 b2e3d87f Nick Thomas
        cpu_to_be64w((uint64_t*)(data + 8), reply.handle);
648 b2e3d87f Nick Thomas
649 b2e3d87f Nick Thomas
        TRACE("Sending data to client");
650 b2e3d87f Nick Thomas
651 b2e3d87f Nick Thomas
        if (write_sync(csock, data,
652 b2e3d87f Nick Thomas
                   request.len + NBD_REPLY_SIZE) !=
653 b2e3d87f Nick Thomas
                   request.len + NBD_REPLY_SIZE) {
654 b2e3d87f Nick Thomas
            LOG("writing to socket failed");
655 b2e3d87f Nick Thomas
            errno = EINVAL;
656 b2e3d87f Nick Thomas
            return -1;
657 b2e3d87f Nick Thomas
        }
658 b2e3d87f Nick Thomas
        break;
659 b2e3d87f Nick Thomas
    case NBD_CMD_WRITE:
660 b2e3d87f Nick Thomas
        TRACE("Request type is WRITE");
661 b2e3d87f Nick Thomas
662 b2e3d87f Nick Thomas
        TRACE("Reading %u byte(s)", request.len);
663 b2e3d87f Nick Thomas
664 b2e3d87f Nick Thomas
        if (read_sync(csock, data, request.len) != request.len) {
665 b2e3d87f Nick Thomas
            LOG("reading from socket failed");
666 b2e3d87f Nick Thomas
            errno = EINVAL;
667 b2e3d87f Nick Thomas
            return -1;
668 b2e3d87f Nick Thomas
        }
669 b2e3d87f Nick Thomas
670 b90fb4b8 Paolo Bonzini
        if (nbdflags & NBD_FLAG_READ_ONLY) {
671 b2e3d87f Nick Thomas
            TRACE("Server is read-only, return error");
672 b2e3d87f Nick Thomas
            reply.error = 1;
673 b2e3d87f Nick Thomas
        } else {
674 b2e3d87f Nick Thomas
            TRACE("Writing to device");
675 b2e3d87f Nick Thomas
676 b2e3d87f Nick Thomas
            if (bdrv_write(bs, (request.from + dev_offset) / 512,
677 b2e3d87f Nick Thomas
                       data, request.len / 512) == -1) {
678 b2e3d87f Nick Thomas
                LOG("writing to file failed");
679 b2e3d87f Nick Thomas
                errno = EINVAL;
680 b2e3d87f Nick Thomas
                return -1;
681 b2e3d87f Nick Thomas
            }
682 b2e3d87f Nick Thomas
683 b2e3d87f Nick Thomas
            *offset += request.len;
684 b2e3d87f Nick Thomas
        }
685 b2e3d87f Nick Thomas
686 b2e3d87f Nick Thomas
        if (nbd_send_reply(csock, &reply) == -1)
687 b2e3d87f Nick Thomas
            return -1;
688 b2e3d87f Nick Thomas
        break;
689 b2e3d87f Nick Thomas
    case NBD_CMD_DISC:
690 b2e3d87f Nick Thomas
        TRACE("Request type is DISCONNECT");
691 b2e3d87f Nick Thomas
        errno = 0;
692 b2e3d87f Nick Thomas
        return 1;
693 b2e3d87f Nick Thomas
    default:
694 b2e3d87f Nick Thomas
        LOG("invalid request type (%u) received", request.type);
695 b2e3d87f Nick Thomas
        errno = EINVAL;
696 b2e3d87f Nick Thomas
        return -1;
697 b2e3d87f Nick Thomas
    }
698 b2e3d87f Nick Thomas
699 b2e3d87f Nick Thomas
    TRACE("Request/Reply complete");
700 b2e3d87f Nick Thomas
701 b2e3d87f Nick Thomas
    return 0;
702 7a5ca864 bellard
}