Statistics
| Branch: | Revision:

root / nbd.c @ 4dad7f1e

History | View | Annotate | Download (16.8 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 7a5ca864 bellard
21 7a5ca864 bellard
#include <errno.h>
22 7a5ca864 bellard
#include <string.h>
23 03ff3ca3 aliguori
#ifndef _WIN32
24 7a5ca864 bellard
#include <sys/ioctl.h>
25 03ff3ca3 aliguori
#endif
26 5dc2eec9 Andreas Färber
#if defined(__sun__) || defined(__HAIKU__)
27 7e00eb9b aliguori
#include <sys/ioccom.h>
28 7e00eb9b aliguori
#endif
29 7a5ca864 bellard
#include <ctype.h>
30 7a5ca864 bellard
#include <inttypes.h>
31 75818250 ths
32 03ff3ca3 aliguori
#include "qemu_socket.h"
33 03ff3ca3 aliguori
34 03ff3ca3 aliguori
//#define DEBUG_NBD
35 03ff3ca3 aliguori
36 03ff3ca3 aliguori
#ifdef DEBUG_NBD
37 75818250 ths
#define TRACE(msg, ...) do { \
38 03ff3ca3 aliguori
    LOG(msg, ## __VA_ARGS__); \
39 75818250 ths
} while(0)
40 03ff3ca3 aliguori
#else
41 03ff3ca3 aliguori
#define TRACE(msg, ...) \
42 03ff3ca3 aliguori
    do { } while (0)
43 03ff3ca3 aliguori
#endif
44 7a5ca864 bellard
45 7a5ca864 bellard
#define LOG(msg, ...) do { \
46 7a5ca864 bellard
    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
47 7a5ca864 bellard
            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
48 7a5ca864 bellard
} while(0)
49 7a5ca864 bellard
50 7a5ca864 bellard
/* This is all part of the "official" NBD API */
51 7a5ca864 bellard
52 b2e3d87f Nick Thomas
#define NBD_REPLY_SIZE          (4 + 4 + 8)
53 7a5ca864 bellard
#define NBD_REQUEST_MAGIC       0x25609513
54 7a5ca864 bellard
#define NBD_REPLY_MAGIC         0x67446698
55 7a5ca864 bellard
56 7a5ca864 bellard
#define NBD_SET_SOCK            _IO(0xab, 0)
57 7a5ca864 bellard
#define NBD_SET_BLKSIZE         _IO(0xab, 1)
58 7a5ca864 bellard
#define NBD_SET_SIZE            _IO(0xab, 2)
59 7a5ca864 bellard
#define NBD_DO_IT               _IO(0xab, 3)
60 7a5ca864 bellard
#define NBD_CLEAR_SOCK          _IO(0xab, 4)
61 7a5ca864 bellard
#define NBD_CLEAR_QUE           _IO(0xab, 5)
62 b2e3d87f Nick Thomas
#define NBD_PRINT_DEBUG         _IO(0xab, 6)
63 b2e3d87f Nick Thomas
#define NBD_SET_SIZE_BLOCKS     _IO(0xab, 7)
64 7a5ca864 bellard
#define NBD_DISCONNECT          _IO(0xab, 8)
65 7a5ca864 bellard
66 b2e3d87f Nick Thomas
#define NBD_OPT_EXPORT_NAME     (1 << 0)
67 1d45f8b5 Laurent Vivier
68 7a5ca864 bellard
/* That's all folks */
69 7a5ca864 bellard
70 75818250 ths
#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
71 75818250 ths
#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
72 7a5ca864 bellard
73 75818250 ths
size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
74 7a5ca864 bellard
{
75 7a5ca864 bellard
    size_t offset = 0;
76 7a5ca864 bellard
77 7a5ca864 bellard
    while (offset < size) {
78 7a5ca864 bellard
        ssize_t len;
79 7a5ca864 bellard
80 7a5ca864 bellard
        if (do_read) {
81 03ff3ca3 aliguori
            len = recv(fd, buffer + offset, size - offset, 0);
82 7a5ca864 bellard
        } else {
83 03ff3ca3 aliguori
            len = send(fd, buffer + offset, size - offset, 0);
84 7a5ca864 bellard
        }
85 7a5ca864 bellard
86 03ff3ca3 aliguori
        if (len == -1)
87 03ff3ca3 aliguori
            errno = socket_error();
88 03ff3ca3 aliguori
89 7a5ca864 bellard
        /* recoverable error */
90 75818250 ths
        if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
91 7a5ca864 bellard
            continue;
92 7a5ca864 bellard
        }
93 7a5ca864 bellard
94 7a5ca864 bellard
        /* eof */
95 7a5ca864 bellard
        if (len == 0) {
96 7a5ca864 bellard
            break;
97 7a5ca864 bellard
        }
98 7a5ca864 bellard
99 7a5ca864 bellard
        /* unrecoverable error */
100 7a5ca864 bellard
        if (len == -1) {
101 7a5ca864 bellard
            return 0;
102 7a5ca864 bellard
        }
103 7a5ca864 bellard
104 7a5ca864 bellard
        offset += len;
105 7a5ca864 bellard
    }
106 7a5ca864 bellard
107 7a5ca864 bellard
    return offset;
108 7a5ca864 bellard
}
109 7a5ca864 bellard
110 c12504ce Nick Thomas
static void combine_addr(char *buf, size_t len, const char* address,
111 c12504ce Nick Thomas
                         uint16_t port)
112 7a5ca864 bellard
{
113 c12504ce Nick Thomas
    /* If the address-part contains a colon, it's an IPv6 IP so needs [] */
114 c12504ce Nick Thomas
    if (strstr(address, ":")) {
115 c12504ce Nick Thomas
        snprintf(buf, len, "[%s]:%u", address, port);
116 c12504ce Nick Thomas
    } else {
117 c12504ce Nick Thomas
        snprintf(buf, len, "%s:%u", address, port);
118 7a5ca864 bellard
    }
119 7a5ca864 bellard
}
120 7a5ca864 bellard
121 c12504ce Nick Thomas
int tcp_socket_outgoing(const char *address, uint16_t port)
122 7a5ca864 bellard
{
123 c12504ce Nick Thomas
    char address_and_port[128];
124 c12504ce Nick Thomas
    combine_addr(address_and_port, 128, address, port);
125 c12504ce Nick Thomas
    return tcp_socket_outgoing_spec(address_and_port);
126 7a5ca864 bellard
}
127 7a5ca864 bellard
128 c12504ce Nick Thomas
int tcp_socket_outgoing_spec(const char *address_and_port)
129 cd831bd7 ths
{
130 c12504ce Nick Thomas
    return inet_connect(address_and_port, SOCK_STREAM);
131 cd831bd7 ths
}
132 cd831bd7 ths
133 c12504ce Nick Thomas
int tcp_socket_incoming(const char *address, uint16_t port)
134 cd831bd7 ths
{
135 c12504ce Nick Thomas
    char address_and_port[128];
136 c12504ce Nick Thomas
    combine_addr(address_and_port, 128, address, port);
137 c12504ce Nick Thomas
    return tcp_socket_incoming_spec(address_and_port);
138 c12504ce Nick Thomas
}
139 cd831bd7 ths
140 c12504ce Nick Thomas
int tcp_socket_incoming_spec(const char *address_and_port)
141 c12504ce Nick Thomas
{
142 c12504ce Nick Thomas
    char *ostr  = NULL;
143 c12504ce Nick Thomas
    int olen = 0;
144 c12504ce Nick Thomas
    return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0);
145 03ff3ca3 aliguori
}
146 c12504ce Nick Thomas
147 03ff3ca3 aliguori
int unix_socket_incoming(const char *path)
148 03ff3ca3 aliguori
{
149 c12504ce Nick Thomas
    char *ostr = NULL;
150 c12504ce Nick Thomas
    int olen = 0;
151 c12504ce Nick Thomas
152 c12504ce Nick Thomas
    return unix_listen(path, ostr, olen);
153 cd831bd7 ths
}
154 cd831bd7 ths
155 03ff3ca3 aliguori
int unix_socket_outgoing(const char *path)
156 03ff3ca3 aliguori
{
157 c12504ce Nick Thomas
    return unix_connect(path);
158 03ff3ca3 aliguori
}
159 cd831bd7 ths
160 7a5ca864 bellard
/* Basic flow
161 7a5ca864 bellard

162 7a5ca864 bellard
   Server         Client
163 7a5ca864 bellard

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