xref: /qemu/hw/vfio-user/proxy.c (revision c6ac52a4d8f7a7c03452454d36b60ac309f0b9ce)
1438d863fSJohn Levon /*
2438d863fSJohn Levon  * vfio protocol over a UNIX socket.
3438d863fSJohn Levon  *
4438d863fSJohn Levon  * Copyright © 2018, 2021 Oracle and/or its affiliates.
5438d863fSJohn Levon  *
6438d863fSJohn Levon  * SPDX-License-Identifier: GPL-2.0-or-later
7438d863fSJohn Levon  */
8438d863fSJohn Levon 
9438d863fSJohn Levon #include "qemu/osdep.h"
10438d863fSJohn Levon #include <sys/ioctl.h>
11438d863fSJohn Levon 
12438d863fSJohn Levon #include "hw/vfio/vfio-device.h"
13438d863fSJohn Levon #include "hw/vfio-user/proxy.h"
140b3d881aSJohn Levon #include "hw/vfio-user/trace.h"
15438d863fSJohn Levon #include "qapi/error.h"
1636227628SJohn Levon #include "qobject/qdict.h"
1736227628SJohn Levon #include "qobject/qjson.h"
1836227628SJohn Levon #include "qobject/qnum.h"
19438d863fSJohn Levon #include "qemu/error-report.h"
20438d863fSJohn Levon #include "qemu/lockable.h"
210b3d881aSJohn Levon #include "qemu/main-loop.h"
22438d863fSJohn Levon #include "system/iothread.h"
23438d863fSJohn Levon 
2436227628SJohn Levon static int wait_time = 5000;   /* wait up to 5 sec for busy servers */
25438d863fSJohn Levon static IOThread *vfio_user_iothread;
26438d863fSJohn Levon 
27438d863fSJohn Levon static void vfio_user_shutdown(VFIOUserProxy *proxy);
280b3d881aSJohn Levon static VFIOUserMsg *vfio_user_getmsg(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
290b3d881aSJohn Levon                                      VFIOUserFDs *fds);
300b3d881aSJohn Levon static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg);
31438d863fSJohn Levon 
320b3d881aSJohn Levon static void vfio_user_recv(void *opaque);
3336227628SJohn Levon static void vfio_user_send(void *opaque);
340b3d881aSJohn Levon static void vfio_user_cb(void *opaque);
350b3d881aSJohn Levon 
360b3d881aSJohn Levon static void vfio_user_request(void *opaque);
370b3d881aSJohn Levon 
380b3d881aSJohn Levon static inline void vfio_user_set_error(VFIOUserHdr *hdr, uint32_t err)
390b3d881aSJohn Levon {
400b3d881aSJohn Levon     hdr->flags |= VFIO_USER_ERROR;
410b3d881aSJohn Levon     hdr->error_reply = err;
420b3d881aSJohn Levon }
43438d863fSJohn Levon 
44438d863fSJohn Levon /*
45438d863fSJohn Levon  * Functions called by main, CPU, or iothread threads
46438d863fSJohn Levon  */
47438d863fSJohn Levon 
48438d863fSJohn Levon static void vfio_user_shutdown(VFIOUserProxy *proxy)
49438d863fSJohn Levon {
50438d863fSJohn Levon     qio_channel_shutdown(proxy->ioc, QIO_CHANNEL_SHUTDOWN_READ, NULL);
51438d863fSJohn Levon     qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx, NULL,
52438d863fSJohn Levon                                    proxy->ctx, NULL, NULL);
53438d863fSJohn Levon }
54438d863fSJohn Levon 
5536227628SJohn Levon /*
5636227628SJohn Levon  * Same return values as qio_channel_writev_full():
5736227628SJohn Levon  *
5836227628SJohn Levon  * QIO_CHANNEL_ERR_BLOCK: *errp not set
5936227628SJohn Levon  * -1: *errp will be populated
6036227628SJohn Levon  * otherwise: bytes written
6136227628SJohn Levon  */
6236227628SJohn Levon static ssize_t vfio_user_send_qio(VFIOUserProxy *proxy, VFIOUserMsg *msg,
6336227628SJohn Levon                                   Error **errp)
6436227628SJohn Levon {
6536227628SJohn Levon     VFIOUserFDs *fds =  msg->fds;
6636227628SJohn Levon     struct iovec iov = {
6736227628SJohn Levon         .iov_base = msg->hdr,
6836227628SJohn Levon         .iov_len = msg->hdr->size,
6936227628SJohn Levon     };
7036227628SJohn Levon     size_t numfds = 0;
7136227628SJohn Levon     int *fdp = NULL;
7236227628SJohn Levon     ssize_t ret;
7336227628SJohn Levon 
7436227628SJohn Levon     if (fds != NULL && fds->send_fds != 0) {
7536227628SJohn Levon         numfds = fds->send_fds;
7636227628SJohn Levon         fdp = fds->fds;
7736227628SJohn Levon     }
7836227628SJohn Levon 
7936227628SJohn Levon     ret = qio_channel_writev_full(proxy->ioc, &iov, 1, fdp, numfds, 0, errp);
8036227628SJohn Levon 
8136227628SJohn Levon     if (ret == -1) {
8236227628SJohn Levon         vfio_user_set_error(msg->hdr, EIO);
8336227628SJohn Levon         vfio_user_shutdown(proxy);
8436227628SJohn Levon     }
8536227628SJohn Levon     trace_vfio_user_send_write(msg->hdr->id, ret);
8636227628SJohn Levon 
8736227628SJohn Levon     return ret;
8836227628SJohn Levon }
8936227628SJohn Levon 
900b3d881aSJohn Levon static VFIOUserMsg *vfio_user_getmsg(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
910b3d881aSJohn Levon                                      VFIOUserFDs *fds)
920b3d881aSJohn Levon {
930b3d881aSJohn Levon     VFIOUserMsg *msg;
940b3d881aSJohn Levon 
950b3d881aSJohn Levon     msg = QTAILQ_FIRST(&proxy->free);
960b3d881aSJohn Levon     if (msg != NULL) {
970b3d881aSJohn Levon         QTAILQ_REMOVE(&proxy->free, msg, next);
980b3d881aSJohn Levon     } else {
990b3d881aSJohn Levon         msg = g_malloc0(sizeof(*msg));
1000b3d881aSJohn Levon         qemu_cond_init(&msg->cv);
1010b3d881aSJohn Levon     }
1020b3d881aSJohn Levon 
1030b3d881aSJohn Levon     msg->hdr = hdr;
1040b3d881aSJohn Levon     msg->fds = fds;
1050b3d881aSJohn Levon     return msg;
1060b3d881aSJohn Levon }
1070b3d881aSJohn Levon 
1080b3d881aSJohn Levon /*
1090b3d881aSJohn Levon  * Recycle a message list entry to the free list.
1100b3d881aSJohn Levon  */
1110b3d881aSJohn Levon static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg)
1120b3d881aSJohn Levon {
1130b3d881aSJohn Levon     if (msg->type == VFIO_MSG_NONE) {
1140b3d881aSJohn Levon         error_printf("vfio_user_recycle - freeing free msg\n");
1150b3d881aSJohn Levon         return;
1160b3d881aSJohn Levon     }
1170b3d881aSJohn Levon 
1180b3d881aSJohn Levon     /* free msg buffer if no one is waiting to consume the reply */
1190b3d881aSJohn Levon     if (msg->type == VFIO_MSG_NOWAIT || msg->type == VFIO_MSG_ASYNC) {
1200b3d881aSJohn Levon         g_free(msg->hdr);
1210b3d881aSJohn Levon         if (msg->fds != NULL) {
1220b3d881aSJohn Levon             g_free(msg->fds);
1230b3d881aSJohn Levon         }
1240b3d881aSJohn Levon     }
1250b3d881aSJohn Levon 
1260b3d881aSJohn Levon     msg->type = VFIO_MSG_NONE;
1270b3d881aSJohn Levon     msg->hdr = NULL;
1280b3d881aSJohn Levon     msg->fds = NULL;
1290b3d881aSJohn Levon     msg->complete = false;
13036227628SJohn Levon     msg->pending = false;
1310b3d881aSJohn Levon     QTAILQ_INSERT_HEAD(&proxy->free, msg, next);
1320b3d881aSJohn Levon }
1330b3d881aSJohn Levon 
13418e899e6SJohn Levon VFIOUserFDs *vfio_user_getfds(int numfds)
1350b3d881aSJohn Levon {
1360b3d881aSJohn Levon     VFIOUserFDs *fds = g_malloc0(sizeof(*fds) + (numfds * sizeof(int)));
1370b3d881aSJohn Levon 
1380b3d881aSJohn Levon     fds->fds = (int *)((char *)fds + sizeof(*fds));
1390b3d881aSJohn Levon 
1400b3d881aSJohn Levon     return fds;
1410b3d881aSJohn Levon }
1420b3d881aSJohn Levon 
143438d863fSJohn Levon /*
144438d863fSJohn Levon  * Functions only called by iothread
145438d863fSJohn Levon  */
146438d863fSJohn Levon 
1470b3d881aSJohn Levon /*
1480b3d881aSJohn Levon  * Process a received message.
1490b3d881aSJohn Levon  */
1500b3d881aSJohn Levon static void vfio_user_process(VFIOUserProxy *proxy, VFIOUserMsg *msg,
1510b3d881aSJohn Levon                               bool isreply)
1520b3d881aSJohn Levon {
1530b3d881aSJohn Levon 
1540b3d881aSJohn Levon     /*
1550b3d881aSJohn Levon      * Replies signal a waiter, if none just check for errors
1560b3d881aSJohn Levon      * and free the message buffer.
1570b3d881aSJohn Levon      *
1580b3d881aSJohn Levon      * Requests get queued for the BH.
1590b3d881aSJohn Levon      */
1600b3d881aSJohn Levon     if (isreply) {
1610b3d881aSJohn Levon         msg->complete = true;
1620b3d881aSJohn Levon         if (msg->type == VFIO_MSG_WAIT) {
1630b3d881aSJohn Levon             qemu_cond_signal(&msg->cv);
1640b3d881aSJohn Levon         } else {
1650b3d881aSJohn Levon             if (msg->hdr->flags & VFIO_USER_ERROR) {
1660b3d881aSJohn Levon                 error_printf("vfio_user_process: error reply on async ");
1670b3d881aSJohn Levon                 error_printf("request command %x error %s\n",
1680b3d881aSJohn Levon                              msg->hdr->command,
1690b3d881aSJohn Levon                              strerror(msg->hdr->error_reply));
1700b3d881aSJohn Levon             }
1710b3d881aSJohn Levon             /* youngest nowait msg has been ack'd */
1720b3d881aSJohn Levon             if (proxy->last_nowait == msg) {
1730b3d881aSJohn Levon                 proxy->last_nowait = NULL;
1740b3d881aSJohn Levon             }
1750b3d881aSJohn Levon             vfio_user_recycle(proxy, msg);
1760b3d881aSJohn Levon         }
1770b3d881aSJohn Levon     } else {
1780b3d881aSJohn Levon         QTAILQ_INSERT_TAIL(&proxy->incoming, msg, next);
1790b3d881aSJohn Levon         qemu_bh_schedule(proxy->req_bh);
1800b3d881aSJohn Levon     }
1810b3d881aSJohn Levon }
1820b3d881aSJohn Levon 
1830b3d881aSJohn Levon /*
1840b3d881aSJohn Levon  * Complete a partial message read
1850b3d881aSJohn Levon  */
1860b3d881aSJohn Levon static int vfio_user_complete(VFIOUserProxy *proxy, Error **errp)
1870b3d881aSJohn Levon {
1880b3d881aSJohn Levon     VFIOUserMsg *msg = proxy->part_recv;
1890b3d881aSJohn Levon     size_t msgleft = proxy->recv_left;
1900b3d881aSJohn Levon     bool isreply;
1910b3d881aSJohn Levon     char *data;
1920b3d881aSJohn Levon     int ret;
1930b3d881aSJohn Levon 
1940b3d881aSJohn Levon     data = (char *)msg->hdr + (msg->hdr->size - msgleft);
1950b3d881aSJohn Levon     while (msgleft > 0) {
1960b3d881aSJohn Levon         ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
1970b3d881aSJohn Levon 
1980b3d881aSJohn Levon         /* error or would block */
1990b3d881aSJohn Levon         if (ret <= 0) {
2000b3d881aSJohn Levon             /* try for rest on next iternation */
2010b3d881aSJohn Levon             if (ret == QIO_CHANNEL_ERR_BLOCK) {
2020b3d881aSJohn Levon                 proxy->recv_left = msgleft;
2030b3d881aSJohn Levon             }
2040b3d881aSJohn Levon             return ret;
2050b3d881aSJohn Levon         }
2060b3d881aSJohn Levon         trace_vfio_user_recv_read(msg->hdr->id, ret);
2070b3d881aSJohn Levon 
2080b3d881aSJohn Levon         msgleft -= ret;
2090b3d881aSJohn Levon         data += ret;
2100b3d881aSJohn Levon     }
2110b3d881aSJohn Levon 
2120b3d881aSJohn Levon     /*
2130b3d881aSJohn Levon      * Read complete message, process it.
2140b3d881aSJohn Levon      */
2150b3d881aSJohn Levon     proxy->part_recv = NULL;
2160b3d881aSJohn Levon     proxy->recv_left = 0;
2170b3d881aSJohn Levon     isreply = (msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REPLY;
2180b3d881aSJohn Levon     vfio_user_process(proxy, msg, isreply);
2190b3d881aSJohn Levon 
2200b3d881aSJohn Levon     /* return positive value */
2210b3d881aSJohn Levon     return 1;
2220b3d881aSJohn Levon }
2230b3d881aSJohn Levon 
2240b3d881aSJohn Levon /*
2250b3d881aSJohn Levon  * Receive and process one incoming message.
2260b3d881aSJohn Levon  *
2270b3d881aSJohn Levon  * For replies, find matching outgoing request and wake any waiters.
2280b3d881aSJohn Levon  * For requests, queue in incoming list and run request BH.
2290b3d881aSJohn Levon  */
2300b3d881aSJohn Levon static int vfio_user_recv_one(VFIOUserProxy *proxy, Error **errp)
2310b3d881aSJohn Levon {
2320b3d881aSJohn Levon     VFIOUserMsg *msg = NULL;
2330b3d881aSJohn Levon     g_autofree int *fdp = NULL;
2340b3d881aSJohn Levon     VFIOUserFDs *reqfds;
2350b3d881aSJohn Levon     VFIOUserHdr hdr;
2360b3d881aSJohn Levon     struct iovec iov = {
2370b3d881aSJohn Levon         .iov_base = &hdr,
2380b3d881aSJohn Levon         .iov_len = sizeof(hdr),
2390b3d881aSJohn Levon     };
2400b3d881aSJohn Levon     bool isreply = false;
2410b3d881aSJohn Levon     int i, ret;
2420b3d881aSJohn Levon     size_t msgleft, numfds = 0;
2430b3d881aSJohn Levon     char *data = NULL;
2440b3d881aSJohn Levon     char *buf = NULL;
2450b3d881aSJohn Levon 
2460b3d881aSJohn Levon     /*
2470b3d881aSJohn Levon      * Complete any partial reads
2480b3d881aSJohn Levon      */
2490b3d881aSJohn Levon     if (proxy->part_recv != NULL) {
2500b3d881aSJohn Levon         ret = vfio_user_complete(proxy, errp);
2510b3d881aSJohn Levon 
2520b3d881aSJohn Levon         /* still not complete, try later */
2530b3d881aSJohn Levon         if (ret == QIO_CHANNEL_ERR_BLOCK) {
2540b3d881aSJohn Levon             return ret;
2550b3d881aSJohn Levon         }
2560b3d881aSJohn Levon 
2570b3d881aSJohn Levon         if (ret <= 0) {
2580b3d881aSJohn Levon             goto fatal;
2590b3d881aSJohn Levon         }
2600b3d881aSJohn Levon         /* else fall into reading another msg */
2610b3d881aSJohn Levon     }
2620b3d881aSJohn Levon 
2630b3d881aSJohn Levon     /*
2640b3d881aSJohn Levon      * Read header
2650b3d881aSJohn Levon      */
2660b3d881aSJohn Levon     ret = qio_channel_readv_full(proxy->ioc, &iov, 1, &fdp, &numfds, 0,
2670b3d881aSJohn Levon                                  errp);
2680b3d881aSJohn Levon     if (ret == QIO_CHANNEL_ERR_BLOCK) {
2690b3d881aSJohn Levon         return ret;
2700b3d881aSJohn Levon     }
2710b3d881aSJohn Levon 
2720b3d881aSJohn Levon     /* read error or other side closed connection */
2730b3d881aSJohn Levon     if (ret <= 0) {
2740b3d881aSJohn Levon         goto fatal;
2750b3d881aSJohn Levon     }
2760b3d881aSJohn Levon 
2770b3d881aSJohn Levon     if (ret < sizeof(hdr)) {
2780b3d881aSJohn Levon         error_setg(errp, "short read of header");
2790b3d881aSJohn Levon         goto fatal;
2800b3d881aSJohn Levon     }
2810b3d881aSJohn Levon 
2820b3d881aSJohn Levon     /*
2830b3d881aSJohn Levon      * Validate header
2840b3d881aSJohn Levon      */
2850b3d881aSJohn Levon     if (hdr.size < sizeof(VFIOUserHdr)) {
2860b3d881aSJohn Levon         error_setg(errp, "bad header size");
2870b3d881aSJohn Levon         goto fatal;
2880b3d881aSJohn Levon     }
2890b3d881aSJohn Levon     switch (hdr.flags & VFIO_USER_TYPE) {
2900b3d881aSJohn Levon     case VFIO_USER_REQUEST:
2910b3d881aSJohn Levon         isreply = false;
2920b3d881aSJohn Levon         break;
2930b3d881aSJohn Levon     case VFIO_USER_REPLY:
2940b3d881aSJohn Levon         isreply = true;
2950b3d881aSJohn Levon         break;
2960b3d881aSJohn Levon     default:
2970b3d881aSJohn Levon         error_setg(errp, "unknown message type");
2980b3d881aSJohn Levon         goto fatal;
2990b3d881aSJohn Levon     }
3000b3d881aSJohn Levon     trace_vfio_user_recv_hdr(proxy->sockname, hdr.id, hdr.command, hdr.size,
3010b3d881aSJohn Levon                              hdr.flags);
3020b3d881aSJohn Levon 
3030b3d881aSJohn Levon     /*
3040b3d881aSJohn Levon      * For replies, find the matching pending request.
3050b3d881aSJohn Levon      * For requests, reap incoming FDs.
3060b3d881aSJohn Levon      */
3070b3d881aSJohn Levon     if (isreply) {
3080b3d881aSJohn Levon         QTAILQ_FOREACH(msg, &proxy->pending, next) {
3090b3d881aSJohn Levon             if (hdr.id == msg->id) {
3100b3d881aSJohn Levon                 break;
3110b3d881aSJohn Levon             }
3120b3d881aSJohn Levon         }
3130b3d881aSJohn Levon         if (msg == NULL) {
3140b3d881aSJohn Levon             error_setg(errp, "unexpected reply");
3150b3d881aSJohn Levon             goto err;
3160b3d881aSJohn Levon         }
3170b3d881aSJohn Levon         QTAILQ_REMOVE(&proxy->pending, msg, next);
3180b3d881aSJohn Levon 
3190b3d881aSJohn Levon         /*
3200b3d881aSJohn Levon          * Process any received FDs
3210b3d881aSJohn Levon          */
3220b3d881aSJohn Levon         if (numfds != 0) {
3230b3d881aSJohn Levon             if (msg->fds == NULL || msg->fds->recv_fds < numfds) {
3240b3d881aSJohn Levon                 error_setg(errp, "unexpected FDs");
3250b3d881aSJohn Levon                 goto err;
3260b3d881aSJohn Levon             }
3270b3d881aSJohn Levon             msg->fds->recv_fds = numfds;
3280b3d881aSJohn Levon             memcpy(msg->fds->fds, fdp, numfds * sizeof(int));
3290b3d881aSJohn Levon         }
3300b3d881aSJohn Levon     } else {
3310b3d881aSJohn Levon         if (numfds != 0) {
3320b3d881aSJohn Levon             reqfds = vfio_user_getfds(numfds);
3330b3d881aSJohn Levon             memcpy(reqfds->fds, fdp, numfds * sizeof(int));
3340b3d881aSJohn Levon         } else {
3350b3d881aSJohn Levon             reqfds = NULL;
3360b3d881aSJohn Levon         }
3370b3d881aSJohn Levon     }
3380b3d881aSJohn Levon 
3390b3d881aSJohn Levon     /*
3400b3d881aSJohn Levon      * Put the whole message into a single buffer.
3410b3d881aSJohn Levon      */
3420b3d881aSJohn Levon     if (isreply) {
3430b3d881aSJohn Levon         if (hdr.size > msg->rsize) {
3440b3d881aSJohn Levon             error_setg(errp, "reply larger than recv buffer");
3450b3d881aSJohn Levon             goto err;
3460b3d881aSJohn Levon         }
3470b3d881aSJohn Levon         *msg->hdr = hdr;
3480b3d881aSJohn Levon         data = (char *)msg->hdr + sizeof(hdr);
3490b3d881aSJohn Levon     } else {
350*c6ac52a4SJohn Levon         if (hdr.size > proxy->max_xfer_size + sizeof(VFIOUserDMARW)) {
351*c6ac52a4SJohn Levon             error_setg(errp, "vfio_user_recv request larger than max");
352*c6ac52a4SJohn Levon             goto err;
353*c6ac52a4SJohn Levon         }
3540b3d881aSJohn Levon         buf = g_malloc0(hdr.size);
3550b3d881aSJohn Levon         memcpy(buf, &hdr, sizeof(hdr));
3560b3d881aSJohn Levon         data = buf + sizeof(hdr);
3570b3d881aSJohn Levon         msg = vfio_user_getmsg(proxy, (VFIOUserHdr *)buf, reqfds);
3580b3d881aSJohn Levon         msg->type = VFIO_MSG_REQ;
3590b3d881aSJohn Levon     }
3600b3d881aSJohn Levon 
3610b3d881aSJohn Levon     /*
3620b3d881aSJohn Levon      * Read rest of message.
3630b3d881aSJohn Levon      */
3640b3d881aSJohn Levon     msgleft = hdr.size - sizeof(hdr);
3650b3d881aSJohn Levon     while (msgleft > 0) {
3660b3d881aSJohn Levon         ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
3670b3d881aSJohn Levon 
3680b3d881aSJohn Levon         /* prepare to complete read on next iternation */
3690b3d881aSJohn Levon         if (ret == QIO_CHANNEL_ERR_BLOCK) {
3700b3d881aSJohn Levon             proxy->part_recv = msg;
3710b3d881aSJohn Levon             proxy->recv_left = msgleft;
3720b3d881aSJohn Levon             return ret;
3730b3d881aSJohn Levon         }
3740b3d881aSJohn Levon 
3750b3d881aSJohn Levon         if (ret <= 0) {
3760b3d881aSJohn Levon             goto fatal;
3770b3d881aSJohn Levon         }
3780b3d881aSJohn Levon         trace_vfio_user_recv_read(hdr.id, ret);
3790b3d881aSJohn Levon 
3800b3d881aSJohn Levon         msgleft -= ret;
3810b3d881aSJohn Levon         data += ret;
3820b3d881aSJohn Levon     }
3830b3d881aSJohn Levon 
3840b3d881aSJohn Levon     vfio_user_process(proxy, msg, isreply);
3850b3d881aSJohn Levon     return 0;
3860b3d881aSJohn Levon 
3870b3d881aSJohn Levon     /*
3880b3d881aSJohn Levon      * fatal means the other side closed or we don't trust the stream
3890b3d881aSJohn Levon      * err means this message is corrupt
3900b3d881aSJohn Levon      */
3910b3d881aSJohn Levon fatal:
3920b3d881aSJohn Levon     vfio_user_shutdown(proxy);
3930b3d881aSJohn Levon     proxy->state = VFIO_PROXY_ERROR;
3940b3d881aSJohn Levon 
3950b3d881aSJohn Levon     /* set error if server side closed */
3960b3d881aSJohn Levon     if (ret == 0) {
3970b3d881aSJohn Levon         error_setg(errp, "server closed socket");
3980b3d881aSJohn Levon     }
3990b3d881aSJohn Levon 
4000b3d881aSJohn Levon err:
4010b3d881aSJohn Levon     for (i = 0; i < numfds; i++) {
4020b3d881aSJohn Levon         close(fdp[i]);
4030b3d881aSJohn Levon     }
4040b3d881aSJohn Levon     if (isreply && msg != NULL) {
4050b3d881aSJohn Levon         /* force an error to keep sending thread from hanging */
4060b3d881aSJohn Levon         vfio_user_set_error(msg->hdr, EINVAL);
4070b3d881aSJohn Levon         msg->complete = true;
4080b3d881aSJohn Levon         qemu_cond_signal(&msg->cv);
4090b3d881aSJohn Levon     }
4100b3d881aSJohn Levon     return -1;
4110b3d881aSJohn Levon }
4120b3d881aSJohn Levon 
4130b3d881aSJohn Levon static void vfio_user_recv(void *opaque)
4140b3d881aSJohn Levon {
4150b3d881aSJohn Levon     VFIOUserProxy *proxy = opaque;
4160b3d881aSJohn Levon 
4170b3d881aSJohn Levon     QEMU_LOCK_GUARD(&proxy->lock);
4180b3d881aSJohn Levon 
4190b3d881aSJohn Levon     if (proxy->state == VFIO_PROXY_CONNECTED) {
4200b3d881aSJohn Levon         Error *local_err = NULL;
4210b3d881aSJohn Levon 
4220b3d881aSJohn Levon         while (vfio_user_recv_one(proxy, &local_err) == 0) {
4230b3d881aSJohn Levon             ;
4240b3d881aSJohn Levon         }
4250b3d881aSJohn Levon 
4260b3d881aSJohn Levon         if (local_err != NULL) {
4270b3d881aSJohn Levon             error_report_err(local_err);
4280b3d881aSJohn Levon         }
4290b3d881aSJohn Levon     }
4300b3d881aSJohn Levon }
4310b3d881aSJohn Levon 
43236227628SJohn Levon /*
43336227628SJohn Levon  * Send a single message, same return semantics as vfio_user_send_qio().
43436227628SJohn Levon  *
43536227628SJohn Levon  * Sent async messages are freed, others are moved to pending queue.
43636227628SJohn Levon  */
43736227628SJohn Levon static ssize_t vfio_user_send_one(VFIOUserProxy *proxy, Error **errp)
43836227628SJohn Levon {
43936227628SJohn Levon     VFIOUserMsg *msg;
44036227628SJohn Levon     ssize_t ret;
44136227628SJohn Levon 
44236227628SJohn Levon     msg = QTAILQ_FIRST(&proxy->outgoing);
44336227628SJohn Levon     ret = vfio_user_send_qio(proxy, msg, errp);
44436227628SJohn Levon     if (ret < 0) {
44536227628SJohn Levon         return ret;
44636227628SJohn Levon     }
44736227628SJohn Levon 
44836227628SJohn Levon     QTAILQ_REMOVE(&proxy->outgoing, msg, next);
44936227628SJohn Levon     if (msg->type == VFIO_MSG_ASYNC) {
45036227628SJohn Levon         vfio_user_recycle(proxy, msg);
45136227628SJohn Levon     } else {
45236227628SJohn Levon         QTAILQ_INSERT_TAIL(&proxy->pending, msg, next);
45336227628SJohn Levon         msg->pending = true;
45436227628SJohn Levon     }
45536227628SJohn Levon 
45636227628SJohn Levon     return ret;
45736227628SJohn Levon }
45836227628SJohn Levon 
45936227628SJohn Levon /*
46036227628SJohn Levon  * Send messages from outgoing queue when the socket buffer has space.
46136227628SJohn Levon  * If we deplete 'outgoing', remove ourselves from the poll list.
46236227628SJohn Levon  */
46336227628SJohn Levon static void vfio_user_send(void *opaque)
46436227628SJohn Levon {
46536227628SJohn Levon     VFIOUserProxy *proxy = opaque;
46636227628SJohn Levon 
46736227628SJohn Levon     QEMU_LOCK_GUARD(&proxy->lock);
46836227628SJohn Levon 
46936227628SJohn Levon     if (proxy->state == VFIO_PROXY_CONNECTED) {
47036227628SJohn Levon         while (!QTAILQ_EMPTY(&proxy->outgoing)) {
47136227628SJohn Levon             Error *local_err = NULL;
47236227628SJohn Levon             int ret;
47336227628SJohn Levon 
47436227628SJohn Levon             ret = vfio_user_send_one(proxy, &local_err);
47536227628SJohn Levon 
47636227628SJohn Levon             if (ret == QIO_CHANNEL_ERR_BLOCK) {
47736227628SJohn Levon                 return;
47836227628SJohn Levon             } else if (ret == -1) {
47936227628SJohn Levon                 error_report_err(local_err);
48036227628SJohn Levon                 return;
48136227628SJohn Levon             }
48236227628SJohn Levon         }
48336227628SJohn Levon         qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
48436227628SJohn Levon                                        vfio_user_recv, NULL, NULL, proxy);
48536227628SJohn Levon     }
48636227628SJohn Levon }
48736227628SJohn Levon 
488438d863fSJohn Levon static void vfio_user_cb(void *opaque)
489438d863fSJohn Levon {
490438d863fSJohn Levon     VFIOUserProxy *proxy = opaque;
491438d863fSJohn Levon 
492438d863fSJohn Levon     QEMU_LOCK_GUARD(&proxy->lock);
493438d863fSJohn Levon 
494438d863fSJohn Levon     proxy->state = VFIO_PROXY_CLOSED;
495438d863fSJohn Levon     qemu_cond_signal(&proxy->close_cv);
496438d863fSJohn Levon }
497438d863fSJohn Levon 
498438d863fSJohn Levon 
499438d863fSJohn Levon /*
500438d863fSJohn Levon  * Functions called by main or CPU threads
501438d863fSJohn Levon  */
502438d863fSJohn Levon 
5030b3d881aSJohn Levon /*
5040b3d881aSJohn Levon  * Process incoming requests.
5050b3d881aSJohn Levon  *
5060b3d881aSJohn Levon  * The bus-specific callback has the form:
5070b3d881aSJohn Levon  *    request(opaque, msg)
5080b3d881aSJohn Levon  * where 'opaque' was specified in vfio_user_set_handler
5090b3d881aSJohn Levon  * and 'msg' is the inbound message.
5100b3d881aSJohn Levon  *
5110b3d881aSJohn Levon  * The callback is responsible for disposing of the message buffer,
5120b3d881aSJohn Levon  * usually by re-using it when calling vfio_send_reply or vfio_send_error,
5130b3d881aSJohn Levon  * both of which free their message buffer when the reply is sent.
5140b3d881aSJohn Levon  *
5150b3d881aSJohn Levon  * If the callback uses a new buffer, it needs to free the old one.
5160b3d881aSJohn Levon  */
5170b3d881aSJohn Levon static void vfio_user_request(void *opaque)
5180b3d881aSJohn Levon {
5190b3d881aSJohn Levon     VFIOUserProxy *proxy = opaque;
5200b3d881aSJohn Levon     VFIOUserMsgQ new, free;
5210b3d881aSJohn Levon     VFIOUserMsg *msg, *m1;
5220b3d881aSJohn Levon 
5230b3d881aSJohn Levon     /* reap all incoming */
5240b3d881aSJohn Levon     QTAILQ_INIT(&new);
5250b3d881aSJohn Levon     WITH_QEMU_LOCK_GUARD(&proxy->lock) {
5260b3d881aSJohn Levon         QTAILQ_FOREACH_SAFE(msg, &proxy->incoming, next, m1) {
5270b3d881aSJohn Levon             QTAILQ_REMOVE(&proxy->incoming, msg, next);
5280b3d881aSJohn Levon             QTAILQ_INSERT_TAIL(&new, msg, next);
5290b3d881aSJohn Levon         }
5300b3d881aSJohn Levon     }
5310b3d881aSJohn Levon 
5320b3d881aSJohn Levon     /* process list */
5330b3d881aSJohn Levon     QTAILQ_INIT(&free);
5340b3d881aSJohn Levon     QTAILQ_FOREACH_SAFE(msg, &new, next, m1) {
5350b3d881aSJohn Levon         QTAILQ_REMOVE(&new, msg, next);
5360b3d881aSJohn Levon         trace_vfio_user_recv_request(msg->hdr->command);
5370b3d881aSJohn Levon         proxy->request(proxy->req_arg, msg);
5380b3d881aSJohn Levon         QTAILQ_INSERT_HEAD(&free, msg, next);
5390b3d881aSJohn Levon     }
5400b3d881aSJohn Levon 
5410b3d881aSJohn Levon     /* free list */
5420b3d881aSJohn Levon     WITH_QEMU_LOCK_GUARD(&proxy->lock) {
5430b3d881aSJohn Levon         QTAILQ_FOREACH_SAFE(msg, &free, next, m1) {
5440b3d881aSJohn Levon             vfio_user_recycle(proxy, msg);
5450b3d881aSJohn Levon         }
5460b3d881aSJohn Levon     }
5470b3d881aSJohn Levon }
5480b3d881aSJohn Levon 
54936227628SJohn Levon /*
55036227628SJohn Levon  * Messages are queued onto the proxy's outgoing list.
55136227628SJohn Levon  *
55236227628SJohn Levon  * It handles 3 types of messages:
55336227628SJohn Levon  *
55436227628SJohn Levon  * async messages - replies and posted writes
55536227628SJohn Levon  *
55636227628SJohn Levon  * There will be no reply from the server, so message
55736227628SJohn Levon  * buffers are freed after they're sent.
55836227628SJohn Levon  *
55936227628SJohn Levon  * nowait messages - map/unmap during address space transactions
56036227628SJohn Levon  *
56136227628SJohn Levon  * These are also sent async, but a reply is expected so that
56236227628SJohn Levon  * vfio_wait_reqs() can wait for the youngest nowait request.
56336227628SJohn Levon  * They transition from the outgoing list to the pending list
56436227628SJohn Levon  * when sent, and are freed when the reply is received.
56536227628SJohn Levon  *
56636227628SJohn Levon  * wait messages - all other requests
56736227628SJohn Levon  *
56836227628SJohn Levon  * The reply to these messages is waited for by their caller.
56936227628SJohn Levon  * They also transition from outgoing to pending when sent, but
57036227628SJohn Levon  * the message buffer is returned to the caller with the reply
57136227628SJohn Levon  * contents.  The caller is responsible for freeing these messages.
57236227628SJohn Levon  *
57336227628SJohn Levon  * As an optimization, if the outgoing list and the socket send
57436227628SJohn Levon  * buffer are empty, the message is sent inline instead of being
57536227628SJohn Levon  * added to the outgoing list.  The rest of the transitions are
57636227628SJohn Levon  * unchanged.
57736227628SJohn Levon  */
57836227628SJohn Levon static bool vfio_user_send_queued(VFIOUserProxy *proxy, VFIOUserMsg *msg,
57936227628SJohn Levon                                   Error **errp)
58036227628SJohn Levon {
58136227628SJohn Levon     int ret;
58236227628SJohn Levon 
58336227628SJohn Levon     /*
58436227628SJohn Levon      * Unsent outgoing msgs - add to tail
58536227628SJohn Levon      */
58636227628SJohn Levon     if (!QTAILQ_EMPTY(&proxy->outgoing)) {
58736227628SJohn Levon         QTAILQ_INSERT_TAIL(&proxy->outgoing, msg, next);
58836227628SJohn Levon         return true;
58936227628SJohn Levon     }
59036227628SJohn Levon 
59136227628SJohn Levon     /*
59236227628SJohn Levon      * Try inline - if blocked, queue it and kick send poller
59336227628SJohn Levon      */
59436227628SJohn Levon     if (proxy->flags & VFIO_PROXY_FORCE_QUEUED) {
59536227628SJohn Levon         ret = QIO_CHANNEL_ERR_BLOCK;
59636227628SJohn Levon     } else {
59736227628SJohn Levon         ret = vfio_user_send_qio(proxy, msg, errp);
59836227628SJohn Levon     }
59936227628SJohn Levon 
60036227628SJohn Levon     if (ret == QIO_CHANNEL_ERR_BLOCK) {
60136227628SJohn Levon         QTAILQ_INSERT_HEAD(&proxy->outgoing, msg, next);
60236227628SJohn Levon         qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
60336227628SJohn Levon                                        vfio_user_recv, proxy->ctx,
60436227628SJohn Levon                                        vfio_user_send, proxy);
60536227628SJohn Levon         return true;
60636227628SJohn Levon     }
60736227628SJohn Levon     if (ret == -1) {
60836227628SJohn Levon         return false;
60936227628SJohn Levon     }
61036227628SJohn Levon 
61136227628SJohn Levon     /*
61236227628SJohn Levon      * Sent - free async, add others to pending
61336227628SJohn Levon      */
61436227628SJohn Levon     if (msg->type == VFIO_MSG_ASYNC) {
61536227628SJohn Levon         vfio_user_recycle(proxy, msg);
61636227628SJohn Levon     } else {
61736227628SJohn Levon         QTAILQ_INSERT_TAIL(&proxy->pending, msg, next);
61836227628SJohn Levon         msg->pending = true;
61936227628SJohn Levon     }
62036227628SJohn Levon 
62136227628SJohn Levon     return true;
62236227628SJohn Levon }
62336227628SJohn Levon 
62436227628SJohn Levon /*
62518e899e6SJohn Levon  * nowait send - vfio_wait_reqs() can wait for it later
62618e899e6SJohn Levon  *
62718e899e6SJohn Levon  * Returns false if we did not successfully receive a reply message, in which
62818e899e6SJohn Levon  * case @errp will be populated.
62918e899e6SJohn Levon  *
63018e899e6SJohn Levon  * In either case, ownership of @hdr and @fds is taken, and the caller must
63118e899e6SJohn Levon  * *not* free them itself.
63218e899e6SJohn Levon  */
63318e899e6SJohn Levon bool vfio_user_send_nowait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
63418e899e6SJohn Levon                            VFIOUserFDs *fds, int rsize, Error **errp)
63518e899e6SJohn Levon {
63618e899e6SJohn Levon     VFIOUserMsg *msg;
63718e899e6SJohn Levon 
63818e899e6SJohn Levon     QEMU_LOCK_GUARD(&proxy->lock);
63918e899e6SJohn Levon 
64018e899e6SJohn Levon     msg = vfio_user_getmsg(proxy, hdr, fds);
64118e899e6SJohn Levon     msg->id = hdr->id;
64218e899e6SJohn Levon     msg->rsize = rsize ? rsize : hdr->size;
64318e899e6SJohn Levon     msg->type = VFIO_MSG_NOWAIT;
64418e899e6SJohn Levon 
64518e899e6SJohn Levon     if (hdr->flags & VFIO_USER_NO_REPLY) {
64618e899e6SJohn Levon         error_setg_errno(errp, EINVAL, "%s on NO_REPLY message", __func__);
64718e899e6SJohn Levon         vfio_user_recycle(proxy, msg);
64818e899e6SJohn Levon         return false;
64918e899e6SJohn Levon     }
65018e899e6SJohn Levon 
65118e899e6SJohn Levon     if (!vfio_user_send_queued(proxy, msg, errp)) {
65218e899e6SJohn Levon         vfio_user_recycle(proxy, msg);
65318e899e6SJohn Levon         return false;
65418e899e6SJohn Levon     }
65518e899e6SJohn Levon 
65618e899e6SJohn Levon     proxy->last_nowait = msg;
65718e899e6SJohn Levon 
65818e899e6SJohn Levon     return true;
65918e899e6SJohn Levon }
66018e899e6SJohn Levon 
66118e899e6SJohn Levon /*
66236227628SJohn Levon  * Returns false if we did not successfully receive a reply message, in which
66336227628SJohn Levon  * case @errp will be populated.
66436227628SJohn Levon  *
66536227628SJohn Levon  * In either case, the caller must free @hdr and @fds if needed.
66636227628SJohn Levon  */
6673bdb738bSJohn Levon bool vfio_user_send_wait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
66836227628SJohn Levon                          VFIOUserFDs *fds, int rsize, Error **errp)
66936227628SJohn Levon {
67036227628SJohn Levon     VFIOUserMsg *msg;
67136227628SJohn Levon     bool ok = false;
67236227628SJohn Levon 
67336227628SJohn Levon     if (hdr->flags & VFIO_USER_NO_REPLY) {
67436227628SJohn Levon         error_setg_errno(errp, EINVAL, "%s on NO_REPLY message", __func__);
67536227628SJohn Levon         return false;
67636227628SJohn Levon     }
67736227628SJohn Levon 
67836227628SJohn Levon     qemu_mutex_lock(&proxy->lock);
67936227628SJohn Levon 
68036227628SJohn Levon     msg = vfio_user_getmsg(proxy, hdr, fds);
68136227628SJohn Levon     msg->id = hdr->id;
68236227628SJohn Levon     msg->rsize = rsize ? rsize : hdr->size;
68336227628SJohn Levon     msg->type = VFIO_MSG_WAIT;
68436227628SJohn Levon 
68536227628SJohn Levon     ok = vfio_user_send_queued(proxy, msg, errp);
68636227628SJohn Levon 
68736227628SJohn Levon     if (ok) {
68836227628SJohn Levon         while (!msg->complete) {
68936227628SJohn Levon             if (!qemu_cond_timedwait(&msg->cv, &proxy->lock, wait_time)) {
69036227628SJohn Levon                 VFIOUserMsgQ *list;
69136227628SJohn Levon 
69236227628SJohn Levon                 list = msg->pending ? &proxy->pending : &proxy->outgoing;
69336227628SJohn Levon                 QTAILQ_REMOVE(list, msg, next);
69436227628SJohn Levon                 error_setg_errno(errp, ETIMEDOUT,
69536227628SJohn Levon                                  "timed out waiting for reply");
69636227628SJohn Levon                 ok = false;
69736227628SJohn Levon                 break;
69836227628SJohn Levon             }
69936227628SJohn Levon         }
70036227628SJohn Levon     }
70136227628SJohn Levon 
70236227628SJohn Levon     vfio_user_recycle(proxy, msg);
70336227628SJohn Levon 
70436227628SJohn Levon     qemu_mutex_unlock(&proxy->lock);
70536227628SJohn Levon 
70636227628SJohn Levon     return ok;
70736227628SJohn Levon }
7080b3d881aSJohn Levon 
709*c6ac52a4SJohn Levon /*
710*c6ac52a4SJohn Levon  * async send - msg can be queued, but will be freed when sent
711*c6ac52a4SJohn Levon  *
712*c6ac52a4SJohn Levon  * Returns false on failure, in which case @errp will be populated.
713*c6ac52a4SJohn Levon  *
714*c6ac52a4SJohn Levon  * In either case, ownership of @hdr and @fds is taken, and the caller must
715*c6ac52a4SJohn Levon  * *not* free them itself.
716*c6ac52a4SJohn Levon  */
717*c6ac52a4SJohn Levon static bool vfio_user_send_async(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
718*c6ac52a4SJohn Levon                                  VFIOUserFDs *fds, Error **errp)
719*c6ac52a4SJohn Levon {
720*c6ac52a4SJohn Levon     VFIOUserMsg *msg;
721*c6ac52a4SJohn Levon 
722*c6ac52a4SJohn Levon     QEMU_LOCK_GUARD(&proxy->lock);
723*c6ac52a4SJohn Levon 
724*c6ac52a4SJohn Levon     msg = vfio_user_getmsg(proxy, hdr, fds);
725*c6ac52a4SJohn Levon     msg->id = hdr->id;
726*c6ac52a4SJohn Levon     msg->rsize = 0;
727*c6ac52a4SJohn Levon     msg->type = VFIO_MSG_ASYNC;
728*c6ac52a4SJohn Levon 
729*c6ac52a4SJohn Levon     if (!(hdr->flags & (VFIO_USER_NO_REPLY | VFIO_USER_REPLY))) {
730*c6ac52a4SJohn Levon         error_setg_errno(errp, EINVAL, "%s on sync message", __func__);
731*c6ac52a4SJohn Levon         vfio_user_recycle(proxy, msg);
732*c6ac52a4SJohn Levon         return false;
733*c6ac52a4SJohn Levon     }
734*c6ac52a4SJohn Levon 
735*c6ac52a4SJohn Levon     if (!vfio_user_send_queued(proxy, msg, errp)) {
736*c6ac52a4SJohn Levon         vfio_user_recycle(proxy, msg);
737*c6ac52a4SJohn Levon         return false;
738*c6ac52a4SJohn Levon     }
739*c6ac52a4SJohn Levon 
740*c6ac52a4SJohn Levon     return true;
741*c6ac52a4SJohn Levon }
742*c6ac52a4SJohn Levon 
74318e899e6SJohn Levon void vfio_user_wait_reqs(VFIOUserProxy *proxy)
74418e899e6SJohn Levon {
74518e899e6SJohn Levon     VFIOUserMsg *msg;
74618e899e6SJohn Levon 
74718e899e6SJohn Levon     /*
74818e899e6SJohn Levon      * Any DMA map/unmap requests sent in the middle
74918e899e6SJohn Levon      * of a memory region transaction were sent nowait.
75018e899e6SJohn Levon      * Wait for them here.
75118e899e6SJohn Levon      */
75218e899e6SJohn Levon     qemu_mutex_lock(&proxy->lock);
75318e899e6SJohn Levon     if (proxy->last_nowait != NULL) {
75418e899e6SJohn Levon         /*
75518e899e6SJohn Levon          * Change type to WAIT to wait for reply
75618e899e6SJohn Levon          */
75718e899e6SJohn Levon         msg = proxy->last_nowait;
75818e899e6SJohn Levon         msg->type = VFIO_MSG_WAIT;
75918e899e6SJohn Levon         proxy->last_nowait = NULL;
76018e899e6SJohn Levon         while (!msg->complete) {
76118e899e6SJohn Levon             if (!qemu_cond_timedwait(&msg->cv, &proxy->lock, wait_time)) {
76218e899e6SJohn Levon                 VFIOUserMsgQ *list;
76318e899e6SJohn Levon 
76418e899e6SJohn Levon                 list = msg->pending ? &proxy->pending : &proxy->outgoing;
76518e899e6SJohn Levon                 QTAILQ_REMOVE(list, msg, next);
76618e899e6SJohn Levon                 error_printf("vfio_wait_reqs - timed out\n");
76718e899e6SJohn Levon                 break;
76818e899e6SJohn Levon             }
76918e899e6SJohn Levon         }
77018e899e6SJohn Levon 
77118e899e6SJohn Levon         if (msg->hdr->flags & VFIO_USER_ERROR) {
77218e899e6SJohn Levon             error_printf("vfio_user_wait_reqs - error reply on async ");
77318e899e6SJohn Levon             error_printf("request: command %x error %s\n", msg->hdr->command,
77418e899e6SJohn Levon                          strerror(msg->hdr->error_reply));
77518e899e6SJohn Levon         }
77618e899e6SJohn Levon 
77718e899e6SJohn Levon         /*
77818e899e6SJohn Levon          * Change type back to NOWAIT to free
77918e899e6SJohn Levon          */
78018e899e6SJohn Levon         msg->type = VFIO_MSG_NOWAIT;
78118e899e6SJohn Levon         vfio_user_recycle(proxy, msg);
78218e899e6SJohn Levon     }
78318e899e6SJohn Levon 
78418e899e6SJohn Levon     qemu_mutex_unlock(&proxy->lock);
78518e899e6SJohn Levon }
78618e899e6SJohn Levon 
787*c6ac52a4SJohn Levon /*
788*c6ac52a4SJohn Levon  * Reply to an incoming request.
789*c6ac52a4SJohn Levon  */
790*c6ac52a4SJohn Levon void vfio_user_send_reply(VFIOUserProxy *proxy, VFIOUserHdr *hdr, int size)
791*c6ac52a4SJohn Levon {
792*c6ac52a4SJohn Levon     Error *local_err = NULL;
793*c6ac52a4SJohn Levon 
794*c6ac52a4SJohn Levon     if (size < sizeof(VFIOUserHdr)) {
795*c6ac52a4SJohn Levon         error_printf("%s: size too small", __func__);
796*c6ac52a4SJohn Levon         g_free(hdr);
797*c6ac52a4SJohn Levon         return;
798*c6ac52a4SJohn Levon     }
799*c6ac52a4SJohn Levon 
800*c6ac52a4SJohn Levon     /*
801*c6ac52a4SJohn Levon      * convert header to associated reply
802*c6ac52a4SJohn Levon      */
803*c6ac52a4SJohn Levon     hdr->flags = VFIO_USER_REPLY;
804*c6ac52a4SJohn Levon     hdr->size = size;
805*c6ac52a4SJohn Levon 
806*c6ac52a4SJohn Levon     if (!vfio_user_send_async(proxy, hdr, NULL, &local_err)) {
807*c6ac52a4SJohn Levon         error_report_err(local_err);
808*c6ac52a4SJohn Levon     }
809*c6ac52a4SJohn Levon }
810*c6ac52a4SJohn Levon 
811*c6ac52a4SJohn Levon /*
812*c6ac52a4SJohn Levon  * Send an error reply to an incoming request.
813*c6ac52a4SJohn Levon  */
814*c6ac52a4SJohn Levon void vfio_user_send_error(VFIOUserProxy *proxy, VFIOUserHdr *hdr, int error)
815*c6ac52a4SJohn Levon {
816*c6ac52a4SJohn Levon     Error *local_err = NULL;
817*c6ac52a4SJohn Levon 
818*c6ac52a4SJohn Levon     /*
819*c6ac52a4SJohn Levon      * convert header to associated reply
820*c6ac52a4SJohn Levon      */
821*c6ac52a4SJohn Levon     hdr->flags = VFIO_USER_REPLY;
822*c6ac52a4SJohn Levon     hdr->flags |= VFIO_USER_ERROR;
823*c6ac52a4SJohn Levon     hdr->error_reply = error;
824*c6ac52a4SJohn Levon     hdr->size = sizeof(*hdr);
825*c6ac52a4SJohn Levon 
826*c6ac52a4SJohn Levon     if (!vfio_user_send_async(proxy, hdr, NULL, &local_err)) {
827*c6ac52a4SJohn Levon         error_report_err(local_err);
828*c6ac52a4SJohn Levon     }
829*c6ac52a4SJohn Levon }
830*c6ac52a4SJohn Levon 
831*c6ac52a4SJohn Levon /*
832*c6ac52a4SJohn Levon  * Close FDs erroneously received in an incoming request.
833*c6ac52a4SJohn Levon  */
834*c6ac52a4SJohn Levon void vfio_user_putfds(VFIOUserMsg *msg)
835*c6ac52a4SJohn Levon {
836*c6ac52a4SJohn Levon     VFIOUserFDs *fds = msg->fds;
837*c6ac52a4SJohn Levon     int i;
838*c6ac52a4SJohn Levon 
839*c6ac52a4SJohn Levon     for (i = 0; i < fds->recv_fds; i++) {
840*c6ac52a4SJohn Levon         close(fds->fds[i]);
841*c6ac52a4SJohn Levon     }
842*c6ac52a4SJohn Levon     g_free(fds);
843*c6ac52a4SJohn Levon     msg->fds = NULL;
844*c6ac52a4SJohn Levon }
845*c6ac52a4SJohn Levon 
846438d863fSJohn Levon static QLIST_HEAD(, VFIOUserProxy) vfio_user_sockets =
847438d863fSJohn Levon     QLIST_HEAD_INITIALIZER(vfio_user_sockets);
848438d863fSJohn Levon 
849438d863fSJohn Levon VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
850438d863fSJohn Levon {
851438d863fSJohn Levon     VFIOUserProxy *proxy;
852438d863fSJohn Levon     QIOChannelSocket *sioc;
853438d863fSJohn Levon     QIOChannel *ioc;
854438d863fSJohn Levon     char *sockname;
855438d863fSJohn Levon 
856438d863fSJohn Levon     if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
857438d863fSJohn Levon         error_setg(errp, "vfio_user_connect - bad address family");
858438d863fSJohn Levon         return NULL;
859438d863fSJohn Levon     }
860438d863fSJohn Levon     sockname = addr->u.q_unix.path;
861438d863fSJohn Levon 
862438d863fSJohn Levon     sioc = qio_channel_socket_new();
863438d863fSJohn Levon     ioc = QIO_CHANNEL(sioc);
864438d863fSJohn Levon     if (qio_channel_socket_connect_sync(sioc, addr, errp)) {
865438d863fSJohn Levon         object_unref(OBJECT(ioc));
866438d863fSJohn Levon         return NULL;
867438d863fSJohn Levon     }
868438d863fSJohn Levon     qio_channel_set_blocking(ioc, false, NULL);
869438d863fSJohn Levon 
870438d863fSJohn Levon     proxy = g_malloc0(sizeof(VFIOUserProxy));
871438d863fSJohn Levon     proxy->sockname = g_strdup_printf("unix:%s", sockname);
872438d863fSJohn Levon     proxy->ioc = ioc;
87336227628SJohn Levon 
87436227628SJohn Levon     /* init defaults */
87536227628SJohn Levon     proxy->max_xfer_size = VFIO_USER_DEF_MAX_XFER;
87636227628SJohn Levon     proxy->max_send_fds = VFIO_USER_DEF_MAX_FDS;
87736227628SJohn Levon     proxy->max_dma = VFIO_USER_DEF_MAP_MAX;
87836227628SJohn Levon     proxy->dma_pgsizes = VFIO_USER_DEF_PGSIZE;
87936227628SJohn Levon     proxy->max_bitmap = VFIO_USER_DEF_MAX_BITMAP;
88036227628SJohn Levon     proxy->migr_pgsize = VFIO_USER_DEF_PGSIZE;
88136227628SJohn Levon 
882438d863fSJohn Levon     proxy->flags = VFIO_PROXY_CLIENT;
883438d863fSJohn Levon     proxy->state = VFIO_PROXY_CONNECTED;
884438d863fSJohn Levon 
885438d863fSJohn Levon     qemu_mutex_init(&proxy->lock);
886438d863fSJohn Levon     qemu_cond_init(&proxy->close_cv);
887438d863fSJohn Levon 
888438d863fSJohn Levon     if (vfio_user_iothread == NULL) {
889438d863fSJohn Levon         vfio_user_iothread = iothread_create("VFIO user", errp);
890438d863fSJohn Levon     }
891438d863fSJohn Levon 
892438d863fSJohn Levon     proxy->ctx = iothread_get_aio_context(vfio_user_iothread);
8930b3d881aSJohn Levon     proxy->req_bh = qemu_bh_new(vfio_user_request, proxy);
894438d863fSJohn Levon 
895438d863fSJohn Levon     QTAILQ_INIT(&proxy->outgoing);
896438d863fSJohn Levon     QTAILQ_INIT(&proxy->incoming);
897438d863fSJohn Levon     QTAILQ_INIT(&proxy->free);
898438d863fSJohn Levon     QTAILQ_INIT(&proxy->pending);
899438d863fSJohn Levon     QLIST_INSERT_HEAD(&vfio_user_sockets, proxy, next);
900438d863fSJohn Levon 
901438d863fSJohn Levon     return proxy;
902438d863fSJohn Levon }
903438d863fSJohn Levon 
9040b3d881aSJohn Levon void vfio_user_set_handler(VFIODevice *vbasedev,
9050b3d881aSJohn Levon                            void (*handler)(void *opaque, VFIOUserMsg *msg),
9060b3d881aSJohn Levon                            void *req_arg)
9070b3d881aSJohn Levon {
9080b3d881aSJohn Levon     VFIOUserProxy *proxy = vbasedev->proxy;
9090b3d881aSJohn Levon 
9100b3d881aSJohn Levon     proxy->request = handler;
9110b3d881aSJohn Levon     proxy->req_arg = req_arg;
9120b3d881aSJohn Levon     qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
9130b3d881aSJohn Levon                                    vfio_user_recv, NULL, NULL, proxy);
9140b3d881aSJohn Levon }
9150b3d881aSJohn Levon 
916438d863fSJohn Levon void vfio_user_disconnect(VFIOUserProxy *proxy)
917438d863fSJohn Levon {
918438d863fSJohn Levon     VFIOUserMsg *r1, *r2;
919438d863fSJohn Levon 
920438d863fSJohn Levon     qemu_mutex_lock(&proxy->lock);
921438d863fSJohn Levon 
922438d863fSJohn Levon     /* our side is quitting */
923438d863fSJohn Levon     if (proxy->state == VFIO_PROXY_CONNECTED) {
924438d863fSJohn Levon         vfio_user_shutdown(proxy);
925438d863fSJohn Levon         if (!QTAILQ_EMPTY(&proxy->pending)) {
926438d863fSJohn Levon             error_printf("vfio_user_disconnect: outstanding requests\n");
927438d863fSJohn Levon         }
928438d863fSJohn Levon     }
929438d863fSJohn Levon     object_unref(OBJECT(proxy->ioc));
930438d863fSJohn Levon     proxy->ioc = NULL;
9310b3d881aSJohn Levon     qemu_bh_delete(proxy->req_bh);
9320b3d881aSJohn Levon     proxy->req_bh = NULL;
933438d863fSJohn Levon 
934438d863fSJohn Levon     proxy->state = VFIO_PROXY_CLOSING;
935438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->outgoing, next, r2) {
936438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
937438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->outgoing, r1, next);
938438d863fSJohn Levon         g_free(r1);
939438d863fSJohn Levon     }
940438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->incoming, next, r2) {
941438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
942438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->incoming, r1, next);
943438d863fSJohn Levon         g_free(r1);
944438d863fSJohn Levon     }
945438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->pending, next, r2) {
946438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
947438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->pending, r1, next);
948438d863fSJohn Levon         g_free(r1);
949438d863fSJohn Levon     }
950438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->free, next, r2) {
951438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
952438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->free, r1, next);
953438d863fSJohn Levon         g_free(r1);
954438d863fSJohn Levon     }
955438d863fSJohn Levon 
956438d863fSJohn Levon     /*
957438d863fSJohn Levon      * Make sure the iothread isn't blocking anywhere
958438d863fSJohn Levon      * with a ref to this proxy by waiting for a BH
959438d863fSJohn Levon      * handler to run after the proxy fd handlers were
960438d863fSJohn Levon      * deleted above.
961438d863fSJohn Levon      */
962438d863fSJohn Levon     aio_bh_schedule_oneshot(proxy->ctx, vfio_user_cb, proxy);
963438d863fSJohn Levon     qemu_cond_wait(&proxy->close_cv, &proxy->lock);
964438d863fSJohn Levon 
965438d863fSJohn Levon     /* we now hold the only ref to proxy */
966438d863fSJohn Levon     qemu_mutex_unlock(&proxy->lock);
967438d863fSJohn Levon     qemu_cond_destroy(&proxy->close_cv);
968438d863fSJohn Levon     qemu_mutex_destroy(&proxy->lock);
969438d863fSJohn Levon 
970438d863fSJohn Levon     QLIST_REMOVE(proxy, next);
971438d863fSJohn Levon     if (QLIST_EMPTY(&vfio_user_sockets)) {
972438d863fSJohn Levon         iothread_destroy(vfio_user_iothread);
973438d863fSJohn Levon         vfio_user_iothread = NULL;
974438d863fSJohn Levon     }
975438d863fSJohn Levon 
976438d863fSJohn Levon     g_free(proxy->sockname);
977438d863fSJohn Levon     g_free(proxy);
978438d863fSJohn Levon }
97936227628SJohn Levon 
9803bdb738bSJohn Levon void vfio_user_request_msg(VFIOUserHdr *hdr, uint16_t cmd,
98136227628SJohn Levon                            uint32_t size, uint32_t flags)
98236227628SJohn Levon {
98336227628SJohn Levon     static uint16_t next_id;
98436227628SJohn Levon 
98536227628SJohn Levon     hdr->id = qatomic_fetch_inc(&next_id);
98636227628SJohn Levon     hdr->command = cmd;
98736227628SJohn Levon     hdr->size = size;
98836227628SJohn Levon     hdr->flags = (flags & ~VFIO_USER_TYPE) | VFIO_USER_REQUEST;
98936227628SJohn Levon     hdr->error_reply = 0;
99036227628SJohn Levon }
99136227628SJohn Levon 
99236227628SJohn Levon struct cap_entry {
99336227628SJohn Levon     const char *name;
99436227628SJohn Levon     bool (*check)(VFIOUserProxy *proxy, QObject *qobj, Error **errp);
99536227628SJohn Levon };
99636227628SJohn Levon 
99736227628SJohn Levon static bool caps_parse(VFIOUserProxy *proxy, QDict *qdict,
99836227628SJohn Levon                        struct cap_entry caps[], Error **errp)
99936227628SJohn Levon {
100036227628SJohn Levon     QObject *qobj;
100136227628SJohn Levon     struct cap_entry *p;
100236227628SJohn Levon 
100336227628SJohn Levon     for (p = caps; p->name != NULL; p++) {
100436227628SJohn Levon         qobj = qdict_get(qdict, p->name);
100536227628SJohn Levon         if (qobj != NULL) {
100636227628SJohn Levon             if (!p->check(proxy, qobj, errp)) {
100736227628SJohn Levon                 return false;
100836227628SJohn Levon             }
100936227628SJohn Levon             qdict_del(qdict, p->name);
101036227628SJohn Levon         }
101136227628SJohn Levon     }
101236227628SJohn Levon 
101336227628SJohn Levon     /* warning, for now */
101436227628SJohn Levon     if (qdict_size(qdict) != 0) {
101536227628SJohn Levon         warn_report("spurious capabilities");
101636227628SJohn Levon     }
101736227628SJohn Levon     return true;
101836227628SJohn Levon }
101936227628SJohn Levon 
102036227628SJohn Levon static bool check_migr_pgsize(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
102136227628SJohn Levon {
102236227628SJohn Levon     QNum *qn = qobject_to(QNum, qobj);
102336227628SJohn Levon     uint64_t pgsize;
102436227628SJohn Levon 
102536227628SJohn Levon     if (qn == NULL || !qnum_get_try_uint(qn, &pgsize)) {
102636227628SJohn Levon         error_setg(errp, "malformed %s", VFIO_USER_CAP_PGSIZE);
102736227628SJohn Levon         return false;
102836227628SJohn Levon     }
102936227628SJohn Levon 
103036227628SJohn Levon     /* must be larger than default */
103136227628SJohn Levon     if (pgsize & (VFIO_USER_DEF_PGSIZE - 1)) {
103236227628SJohn Levon         error_setg(errp, "pgsize 0x%"PRIx64" too small", pgsize);
103336227628SJohn Levon         return false;
103436227628SJohn Levon     }
103536227628SJohn Levon 
103636227628SJohn Levon     proxy->migr_pgsize = pgsize;
103736227628SJohn Levon     return true;
103836227628SJohn Levon }
103936227628SJohn Levon 
104036227628SJohn Levon static bool check_bitmap(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
104136227628SJohn Levon {
104236227628SJohn Levon     QNum *qn = qobject_to(QNum, qobj);
104336227628SJohn Levon     uint64_t bitmap_size;
104436227628SJohn Levon 
104536227628SJohn Levon     if (qn == NULL || !qnum_get_try_uint(qn, &bitmap_size)) {
104636227628SJohn Levon         error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_BITMAP);
104736227628SJohn Levon         return false;
104836227628SJohn Levon     }
104936227628SJohn Levon 
105036227628SJohn Levon     /* can only lower it */
105136227628SJohn Levon     if (bitmap_size > VFIO_USER_DEF_MAX_BITMAP) {
105236227628SJohn Levon         error_setg(errp, "%s too large", VFIO_USER_CAP_MAX_BITMAP);
105336227628SJohn Levon         return false;
105436227628SJohn Levon     }
105536227628SJohn Levon 
105636227628SJohn Levon     proxy->max_bitmap = bitmap_size;
105736227628SJohn Levon     return true;
105836227628SJohn Levon }
105936227628SJohn Levon 
106036227628SJohn Levon static struct cap_entry caps_migr[] = {
106136227628SJohn Levon     { VFIO_USER_CAP_PGSIZE, check_migr_pgsize },
106236227628SJohn Levon     { VFIO_USER_CAP_MAX_BITMAP, check_bitmap },
106336227628SJohn Levon     { NULL }
106436227628SJohn Levon };
106536227628SJohn Levon 
106636227628SJohn Levon static bool check_max_fds(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
106736227628SJohn Levon {
106836227628SJohn Levon     QNum *qn = qobject_to(QNum, qobj);
106936227628SJohn Levon     uint64_t max_send_fds;
107036227628SJohn Levon 
107136227628SJohn Levon     if (qn == NULL || !qnum_get_try_uint(qn, &max_send_fds) ||
107236227628SJohn Levon         max_send_fds > VFIO_USER_MAX_MAX_FDS) {
107336227628SJohn Levon         error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_FDS);
107436227628SJohn Levon         return false;
107536227628SJohn Levon     }
107636227628SJohn Levon     proxy->max_send_fds = max_send_fds;
107736227628SJohn Levon     return true;
107836227628SJohn Levon }
107936227628SJohn Levon 
108036227628SJohn Levon static bool check_max_xfer(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
108136227628SJohn Levon {
108236227628SJohn Levon     QNum *qn = qobject_to(QNum, qobj);
108336227628SJohn Levon     uint64_t max_xfer_size;
108436227628SJohn Levon 
108536227628SJohn Levon     if (qn == NULL || !qnum_get_try_uint(qn, &max_xfer_size) ||
108636227628SJohn Levon         max_xfer_size > VFIO_USER_MAX_MAX_XFER) {
108736227628SJohn Levon         error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_XFER);
108836227628SJohn Levon         return false;
108936227628SJohn Levon     }
109036227628SJohn Levon     proxy->max_xfer_size = max_xfer_size;
109136227628SJohn Levon     return true;
109236227628SJohn Levon }
109336227628SJohn Levon 
109436227628SJohn Levon static bool check_pgsizes(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
109536227628SJohn Levon {
109636227628SJohn Levon     QNum *qn = qobject_to(QNum, qobj);
109736227628SJohn Levon     uint64_t pgsizes;
109836227628SJohn Levon 
109936227628SJohn Levon     if (qn == NULL || !qnum_get_try_uint(qn, &pgsizes)) {
110036227628SJohn Levon         error_setg(errp, "malformed %s", VFIO_USER_CAP_PGSIZES);
110136227628SJohn Levon         return false;
110236227628SJohn Levon     }
110336227628SJohn Levon 
110436227628SJohn Levon     /* must be larger than default */
110536227628SJohn Levon     if (pgsizes & (VFIO_USER_DEF_PGSIZE - 1)) {
110636227628SJohn Levon         error_setg(errp, "pgsize 0x%"PRIx64" too small", pgsizes);
110736227628SJohn Levon         return false;
110836227628SJohn Levon     }
110936227628SJohn Levon 
111036227628SJohn Levon     proxy->dma_pgsizes = pgsizes;
111136227628SJohn Levon     return true;
111236227628SJohn Levon }
111336227628SJohn Levon 
111436227628SJohn Levon static bool check_max_dma(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
111536227628SJohn Levon {
111636227628SJohn Levon     QNum *qn = qobject_to(QNum, qobj);
111736227628SJohn Levon     uint64_t max_dma;
111836227628SJohn Levon 
111936227628SJohn Levon     if (qn == NULL || !qnum_get_try_uint(qn, &max_dma)) {
112036227628SJohn Levon         error_setg(errp, "malformed %s", VFIO_USER_CAP_MAP_MAX);
112136227628SJohn Levon         return false;
112236227628SJohn Levon     }
112336227628SJohn Levon 
112436227628SJohn Levon     /* can only lower it */
112536227628SJohn Levon     if (max_dma > VFIO_USER_DEF_MAP_MAX) {
112636227628SJohn Levon         error_setg(errp, "%s too large", VFIO_USER_CAP_MAP_MAX);
112736227628SJohn Levon         return false;
112836227628SJohn Levon     }
112936227628SJohn Levon 
113036227628SJohn Levon     proxy->max_dma = max_dma;
113136227628SJohn Levon     return true;
113236227628SJohn Levon }
113336227628SJohn Levon 
113436227628SJohn Levon static bool check_migr(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
113536227628SJohn Levon {
113636227628SJohn Levon     QDict *qdict = qobject_to(QDict, qobj);
113736227628SJohn Levon 
113836227628SJohn Levon     if (qdict == NULL) {
113936227628SJohn Levon         error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_FDS);
114036227628SJohn Levon         return true;
114136227628SJohn Levon     }
114236227628SJohn Levon     return caps_parse(proxy, qdict, caps_migr, errp);
114336227628SJohn Levon }
114436227628SJohn Levon 
114536227628SJohn Levon static struct cap_entry caps_cap[] = {
114636227628SJohn Levon     { VFIO_USER_CAP_MAX_FDS, check_max_fds },
114736227628SJohn Levon     { VFIO_USER_CAP_MAX_XFER, check_max_xfer },
114836227628SJohn Levon     { VFIO_USER_CAP_PGSIZES, check_pgsizes },
114936227628SJohn Levon     { VFIO_USER_CAP_MAP_MAX, check_max_dma },
115036227628SJohn Levon     { VFIO_USER_CAP_MIGR, check_migr },
115136227628SJohn Levon     { NULL }
115236227628SJohn Levon };
115336227628SJohn Levon 
115436227628SJohn Levon static bool check_cap(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
115536227628SJohn Levon {
115636227628SJohn Levon    QDict *qdict = qobject_to(QDict, qobj);
115736227628SJohn Levon 
115836227628SJohn Levon     if (qdict == NULL) {
115936227628SJohn Levon         error_setg(errp, "malformed %s", VFIO_USER_CAP);
116036227628SJohn Levon         return false;
116136227628SJohn Levon     }
116236227628SJohn Levon     return caps_parse(proxy, qdict, caps_cap, errp);
116336227628SJohn Levon }
116436227628SJohn Levon 
116536227628SJohn Levon static struct cap_entry ver_0_0[] = {
116636227628SJohn Levon     { VFIO_USER_CAP, check_cap },
116736227628SJohn Levon     { NULL }
116836227628SJohn Levon };
116936227628SJohn Levon 
117036227628SJohn Levon static bool caps_check(VFIOUserProxy *proxy, int minor, const char *caps,
117136227628SJohn Levon                        Error **errp)
117236227628SJohn Levon {
117336227628SJohn Levon     QObject *qobj;
117436227628SJohn Levon     QDict *qdict;
117536227628SJohn Levon     bool ret;
117636227628SJohn Levon 
117736227628SJohn Levon     qobj = qobject_from_json(caps, NULL);
117836227628SJohn Levon     if (qobj == NULL) {
117936227628SJohn Levon         error_setg(errp, "malformed capabilities %s", caps);
118036227628SJohn Levon         return false;
118136227628SJohn Levon     }
118236227628SJohn Levon     qdict = qobject_to(QDict, qobj);
118336227628SJohn Levon     if (qdict == NULL) {
118436227628SJohn Levon         error_setg(errp, "capabilities %s not an object", caps);
118536227628SJohn Levon         qobject_unref(qobj);
118636227628SJohn Levon         return false;
118736227628SJohn Levon     }
118836227628SJohn Levon     ret = caps_parse(proxy, qdict, ver_0_0, errp);
118936227628SJohn Levon 
119036227628SJohn Levon     qobject_unref(qobj);
119136227628SJohn Levon     return ret;
119236227628SJohn Levon }
119336227628SJohn Levon 
119436227628SJohn Levon static GString *caps_json(void)
119536227628SJohn Levon {
119636227628SJohn Levon     QDict *dict = qdict_new();
119736227628SJohn Levon     QDict *capdict = qdict_new();
119836227628SJohn Levon     QDict *migdict = qdict_new();
119936227628SJohn Levon     GString *str;
120036227628SJohn Levon 
120136227628SJohn Levon     qdict_put_int(migdict, VFIO_USER_CAP_PGSIZE, VFIO_USER_DEF_PGSIZE);
120236227628SJohn Levon     qdict_put_int(migdict, VFIO_USER_CAP_MAX_BITMAP, VFIO_USER_DEF_MAX_BITMAP);
120336227628SJohn Levon     qdict_put_obj(capdict, VFIO_USER_CAP_MIGR, QOBJECT(migdict));
120436227628SJohn Levon 
120536227628SJohn Levon     qdict_put_int(capdict, VFIO_USER_CAP_MAX_FDS, VFIO_USER_MAX_MAX_FDS);
120636227628SJohn Levon     qdict_put_int(capdict, VFIO_USER_CAP_MAX_XFER, VFIO_USER_DEF_MAX_XFER);
120736227628SJohn Levon     qdict_put_int(capdict, VFIO_USER_CAP_PGSIZES, VFIO_USER_DEF_PGSIZE);
120836227628SJohn Levon     qdict_put_int(capdict, VFIO_USER_CAP_MAP_MAX, VFIO_USER_DEF_MAP_MAX);
120936227628SJohn Levon 
121036227628SJohn Levon     qdict_put_obj(dict, VFIO_USER_CAP, QOBJECT(capdict));
121136227628SJohn Levon 
121236227628SJohn Levon     str = qobject_to_json(QOBJECT(dict));
121336227628SJohn Levon     qobject_unref(dict);
121436227628SJohn Levon     return str;
121536227628SJohn Levon }
121636227628SJohn Levon 
121736227628SJohn Levon bool vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp)
121836227628SJohn Levon {
121936227628SJohn Levon     g_autofree VFIOUserVersion *msgp = NULL;
122036227628SJohn Levon     GString *caps;
122136227628SJohn Levon     char *reply;
122236227628SJohn Levon     int size, caplen;
122336227628SJohn Levon 
122436227628SJohn Levon     caps = caps_json();
122536227628SJohn Levon     caplen = caps->len + 1;
122636227628SJohn Levon     size = sizeof(*msgp) + caplen;
122736227628SJohn Levon     msgp = g_malloc0(size);
122836227628SJohn Levon 
122936227628SJohn Levon     vfio_user_request_msg(&msgp->hdr, VFIO_USER_VERSION, size, 0);
123036227628SJohn Levon     msgp->major = VFIO_USER_MAJOR_VER;
123136227628SJohn Levon     msgp->minor = VFIO_USER_MINOR_VER;
123236227628SJohn Levon     memcpy(&msgp->capabilities, caps->str, caplen);
123336227628SJohn Levon     g_string_free(caps, true);
123436227628SJohn Levon     trace_vfio_user_version(msgp->major, msgp->minor, msgp->capabilities);
123536227628SJohn Levon 
123636227628SJohn Levon     if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, errp)) {
123736227628SJohn Levon         return false;
123836227628SJohn Levon     }
123936227628SJohn Levon 
124036227628SJohn Levon     if (msgp->hdr.flags & VFIO_USER_ERROR) {
124136227628SJohn Levon         error_setg_errno(errp, msgp->hdr.error_reply, "version reply");
124236227628SJohn Levon         return false;
124336227628SJohn Levon     }
124436227628SJohn Levon 
124536227628SJohn Levon     if (msgp->major != VFIO_USER_MAJOR_VER ||
124636227628SJohn Levon         msgp->minor > VFIO_USER_MINOR_VER) {
124736227628SJohn Levon         error_setg(errp, "incompatible server version");
124836227628SJohn Levon         return false;
124936227628SJohn Levon     }
125036227628SJohn Levon 
125136227628SJohn Levon     reply = msgp->capabilities;
125236227628SJohn Levon     if (reply[msgp->hdr.size - sizeof(*msgp) - 1] != '\0') {
125336227628SJohn Levon         error_setg(errp, "corrupt version reply");
125436227628SJohn Levon         return false;
125536227628SJohn Levon     }
125636227628SJohn Levon 
125736227628SJohn Levon     if (!caps_check(proxy, msgp->minor, reply, errp)) {
125836227628SJohn Levon         return false;
125936227628SJohn Levon     }
126036227628SJohn Levon 
126136227628SJohn Levon     trace_vfio_user_version(msgp->major, msgp->minor, msgp->capabilities);
126236227628SJohn Levon     return true;
126336227628SJohn Levon }
1264