xref: /qemu/net/vmnet-common.m (revision 993f71ee)
181ad2964SVladislav Yaroshchuk/*
281ad2964SVladislav Yaroshchuk * vmnet-common.m - network client wrapper for Apple vmnet.framework
381ad2964SVladislav Yaroshchuk *
481ad2964SVladislav Yaroshchuk * Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com>
581ad2964SVladislav Yaroshchuk * Copyright(c) 2021 Phillip Tennen <phillip@axleos.com>
681ad2964SVladislav Yaroshchuk *
781ad2964SVladislav Yaroshchuk * This work is licensed under the terms of the GNU GPL, version 2 or later.
881ad2964SVladislav Yaroshchuk * See the COPYING file in the top-level directory.
981ad2964SVladislav Yaroshchuk *
1081ad2964SVladislav Yaroshchuk */
1181ad2964SVladislav Yaroshchuk
1281ad2964SVladislav Yaroshchuk#include "qemu/osdep.h"
1373f99db5SVladislav Yaroshchuk#include "qemu/main-loop.h"
1473f99db5SVladislav Yaroshchuk#include "qemu/log.h"
1581ad2964SVladislav Yaroshchuk#include "qapi/qapi-types-net.h"
1681ad2964SVladislav Yaroshchuk#include "vmnet_int.h"
1781ad2964SVladislav Yaroshchuk#include "clients.h"
1881ad2964SVladislav Yaroshchuk#include "qemu/error-report.h"
1981ad2964SVladislav Yaroshchuk#include "qapi/error.h"
20993f71eeSJoelle van Dyne#include "sysemu/runstate.h"
2181ad2964SVladislav Yaroshchuk
2281ad2964SVladislav Yaroshchuk#include <vmnet/vmnet.h>
2373f99db5SVladislav Yaroshchuk#include <dispatch/dispatch.h>
2473f99db5SVladislav Yaroshchuk
2573f99db5SVladislav Yaroshchuk
2673f99db5SVladislav Yaroshchukstatic void vmnet_send_completed(NetClientState *nc, ssize_t len);
2773f99db5SVladislav Yaroshchuk
2873f99db5SVladislav Yaroshchuk
2973f99db5SVladislav Yaroshchukconst char *vmnet_status_map_str(vmnet_return_t status)
3073f99db5SVladislav Yaroshchuk{
3173f99db5SVladislav Yaroshchuk    switch (status) {
3273f99db5SVladislav Yaroshchuk    case VMNET_SUCCESS:
3373f99db5SVladislav Yaroshchuk        return "success";
3473f99db5SVladislav Yaroshchuk    case VMNET_FAILURE:
3573f99db5SVladislav Yaroshchuk        return "general failure (possibly not enough privileges)";
3673f99db5SVladislav Yaroshchuk    case VMNET_MEM_FAILURE:
3773f99db5SVladislav Yaroshchuk        return "memory allocation failure";
3873f99db5SVladislav Yaroshchuk    case VMNET_INVALID_ARGUMENT:
3973f99db5SVladislav Yaroshchuk        return "invalid argument specified";
4073f99db5SVladislav Yaroshchuk    case VMNET_SETUP_INCOMPLETE:
4173f99db5SVladislav Yaroshchuk        return "interface setup is not complete";
4273f99db5SVladislav Yaroshchuk    case VMNET_INVALID_ACCESS:
4373f99db5SVladislav Yaroshchuk        return "invalid access, permission denied";
4473f99db5SVladislav Yaroshchuk    case VMNET_PACKET_TOO_BIG:
4573f99db5SVladislav Yaroshchuk        return "packet size is larger than MTU";
4673f99db5SVladislav Yaroshchuk    case VMNET_BUFFER_EXHAUSTED:
4773f99db5SVladislav Yaroshchuk        return "buffers exhausted in kernel";
4873f99db5SVladislav Yaroshchuk    case VMNET_TOO_MANY_PACKETS:
4973f99db5SVladislav Yaroshchuk        return "packet count exceeds limit";
5073f99db5SVladislav Yaroshchuk#if defined(MAC_OS_VERSION_11_0) && \
5173f99db5SVladislav Yaroshchuk    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
5273f99db5SVladislav Yaroshchuk    case VMNET_SHARING_SERVICE_BUSY:
5373f99db5SVladislav Yaroshchuk        return "conflict, sharing service is in use";
5473f99db5SVladislav Yaroshchuk#endif
5573f99db5SVladislav Yaroshchuk    default:
5673f99db5SVladislav Yaroshchuk        return "unknown vmnet error";
5773f99db5SVladislav Yaroshchuk    }
5873f99db5SVladislav Yaroshchuk}
5973f99db5SVladislav Yaroshchuk
6073f99db5SVladislav Yaroshchuk
6173f99db5SVladislav Yaroshchuk/**
6273f99db5SVladislav Yaroshchuk * Write packets from QEMU to vmnet interface.
6373f99db5SVladislav Yaroshchuk *
6473f99db5SVladislav Yaroshchuk * vmnet.framework supports iov, but writing more than
6573f99db5SVladislav Yaroshchuk * one iov into vmnet interface fails with
6673f99db5SVladislav Yaroshchuk * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
6773f99db5SVladislav Yaroshchuk * one and passing it to vmnet works fine. That's the
6873f99db5SVladislav Yaroshchuk * reason why receive_iov() left unimplemented. But it still
6973f99db5SVladislav Yaroshchuk * works with good performance having .receive() only.
7073f99db5SVladislav Yaroshchuk */
7173f99db5SVladislav Yaroshchukssize_t vmnet_receive_common(NetClientState *nc,
7273f99db5SVladislav Yaroshchuk                             const uint8_t *buf,
7373f99db5SVladislav Yaroshchuk                             size_t size)
7473f99db5SVladislav Yaroshchuk{
7573f99db5SVladislav Yaroshchuk    VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
7673f99db5SVladislav Yaroshchuk    struct vmpktdesc packet;
7773f99db5SVladislav Yaroshchuk    struct iovec iov;
7873f99db5SVladislav Yaroshchuk    int pkt_cnt;
7973f99db5SVladislav Yaroshchuk    vmnet_return_t if_status;
8073f99db5SVladislav Yaroshchuk
8173f99db5SVladislav Yaroshchuk    if (size > s->max_packet_size) {
8273f99db5SVladislav Yaroshchuk        warn_report("vmnet: packet is too big, %zu > %" PRIu64,
8373f99db5SVladislav Yaroshchuk            packet.vm_pkt_size,
8473f99db5SVladislav Yaroshchuk            s->max_packet_size);
8573f99db5SVladislav Yaroshchuk        return -1;
8673f99db5SVladislav Yaroshchuk    }
8773f99db5SVladislav Yaroshchuk
8873f99db5SVladislav Yaroshchuk    iov.iov_base = (char *) buf;
8973f99db5SVladislav Yaroshchuk    iov.iov_len = size;
9073f99db5SVladislav Yaroshchuk
9173f99db5SVladislav Yaroshchuk    packet.vm_pkt_iovcnt = 1;
9273f99db5SVladislav Yaroshchuk    packet.vm_flags = 0;
9373f99db5SVladislav Yaroshchuk    packet.vm_pkt_size = size;
9473f99db5SVladislav Yaroshchuk    packet.vm_pkt_iov = &iov;
9573f99db5SVladislav Yaroshchuk    pkt_cnt = 1;
9673f99db5SVladislav Yaroshchuk
9773f99db5SVladislav Yaroshchuk    if_status = vmnet_write(s->vmnet_if, &packet, &pkt_cnt);
9873f99db5SVladislav Yaroshchuk    if (if_status != VMNET_SUCCESS) {
9973f99db5SVladislav Yaroshchuk        error_report("vmnet: write error: %s\n",
10073f99db5SVladislav Yaroshchuk                     vmnet_status_map_str(if_status));
10173f99db5SVladislav Yaroshchuk        return -1;
10273f99db5SVladislav Yaroshchuk    }
10373f99db5SVladislav Yaroshchuk
10473f99db5SVladislav Yaroshchuk    if (pkt_cnt) {
10573f99db5SVladislav Yaroshchuk        return size;
10673f99db5SVladislav Yaroshchuk    }
10773f99db5SVladislav Yaroshchuk    return 0;
10873f99db5SVladislav Yaroshchuk}
10973f99db5SVladislav Yaroshchuk
11073f99db5SVladislav Yaroshchuk
11173f99db5SVladislav Yaroshchuk/**
11273f99db5SVladislav Yaroshchuk * Read packets from vmnet interface and write them
11373f99db5SVladislav Yaroshchuk * to temporary buffers in VmnetState.
11473f99db5SVladislav Yaroshchuk *
11573f99db5SVladislav Yaroshchuk * Returns read packets number (may be 0) on success,
11673f99db5SVladislav Yaroshchuk * -1 on error
11773f99db5SVladislav Yaroshchuk */
11873f99db5SVladislav Yaroshchukstatic int vmnet_read_packets(VmnetState *s)
11973f99db5SVladislav Yaroshchuk{
12073f99db5SVladislav Yaroshchuk    assert(s->packets_send_current_pos == s->packets_send_end_pos);
12173f99db5SVladislav Yaroshchuk
12273f99db5SVladislav Yaroshchuk    struct vmpktdesc *packets = s->packets_buf;
12373f99db5SVladislav Yaroshchuk    vmnet_return_t status;
12473f99db5SVladislav Yaroshchuk    int i;
12573f99db5SVladislav Yaroshchuk
12673f99db5SVladislav Yaroshchuk    /* Read as many packets as present */
12773f99db5SVladislav Yaroshchuk    s->packets_send_current_pos = 0;
12873f99db5SVladislav Yaroshchuk    s->packets_send_end_pos = VMNET_PACKETS_LIMIT;
12973f99db5SVladislav Yaroshchuk    for (i = 0; i < s->packets_send_end_pos; ++i) {
13073f99db5SVladislav Yaroshchuk        packets[i].vm_pkt_size = s->max_packet_size;
13173f99db5SVladislav Yaroshchuk        packets[i].vm_pkt_iovcnt = 1;
13273f99db5SVladislav Yaroshchuk        packets[i].vm_flags = 0;
13373f99db5SVladislav Yaroshchuk    }
13473f99db5SVladislav Yaroshchuk
13573f99db5SVladislav Yaroshchuk    status = vmnet_read(s->vmnet_if, packets, &s->packets_send_end_pos);
13673f99db5SVladislav Yaroshchuk    if (status != VMNET_SUCCESS) {
13773f99db5SVladislav Yaroshchuk        error_printf("vmnet: read failed: %s\n",
13873f99db5SVladislav Yaroshchuk                     vmnet_status_map_str(status));
13973f99db5SVladislav Yaroshchuk        s->packets_send_current_pos = 0;
14073f99db5SVladislav Yaroshchuk        s->packets_send_end_pos = 0;
14173f99db5SVladislav Yaroshchuk        return -1;
14273f99db5SVladislav Yaroshchuk    }
14373f99db5SVladislav Yaroshchuk    return s->packets_send_end_pos;
14473f99db5SVladislav Yaroshchuk}
14573f99db5SVladislav Yaroshchuk
14673f99db5SVladislav Yaroshchuk
14773f99db5SVladislav Yaroshchuk/**
14873f99db5SVladislav Yaroshchuk * Write packets from temporary buffers in VmnetState
14973f99db5SVladislav Yaroshchuk * to QEMU.
15073f99db5SVladislav Yaroshchuk */
15173f99db5SVladislav Yaroshchukstatic void vmnet_write_packets_to_qemu(VmnetState *s)
15273f99db5SVladislav Yaroshchuk{
15373f99db5SVladislav Yaroshchuk    while (s->packets_send_current_pos < s->packets_send_end_pos) {
15473f99db5SVladislav Yaroshchuk        ssize_t size = qemu_send_packet_async(&s->nc,
15573f99db5SVladislav Yaroshchuk                                      s->iov_buf[s->packets_send_current_pos].iov_base,
15673f99db5SVladislav Yaroshchuk                                      s->packets_buf[s->packets_send_current_pos].vm_pkt_size,
15773f99db5SVladislav Yaroshchuk                                      vmnet_send_completed);
15873f99db5SVladislav Yaroshchuk
15973f99db5SVladislav Yaroshchuk        if (size == 0) {
16073f99db5SVladislav Yaroshchuk            /* QEMU is not ready to consume more packets -
16173f99db5SVladislav Yaroshchuk             * stop and wait for completion callback call */
16273f99db5SVladislav Yaroshchuk            return;
16373f99db5SVladislav Yaroshchuk        }
16473f99db5SVladislav Yaroshchuk        ++s->packets_send_current_pos;
16573f99db5SVladislav Yaroshchuk    }
16673f99db5SVladislav Yaroshchuk}
16773f99db5SVladislav Yaroshchuk
16873f99db5SVladislav Yaroshchuk
16973f99db5SVladislav Yaroshchuk/**
17073f99db5SVladislav Yaroshchuk * Bottom half callback that transfers packets from vmnet interface
17173f99db5SVladislav Yaroshchuk * to QEMU.
17273f99db5SVladislav Yaroshchuk *
17373f99db5SVladislav Yaroshchuk * The process of transferring packets is three-staged:
17473f99db5SVladislav Yaroshchuk * 1. Handle vmnet event;
17573f99db5SVladislav Yaroshchuk * 2. Read packets from vmnet interface into temporary buffer;
17673f99db5SVladislav Yaroshchuk * 3. Write packets from temporary buffer to QEMU.
17773f99db5SVladislav Yaroshchuk *
17873f99db5SVladislav Yaroshchuk * QEMU may suspend this process on the last stage, returning 0 from
17973f99db5SVladislav Yaroshchuk * qemu_send_packet_async function. If this happens, we should
18073f99db5SVladislav Yaroshchuk * respectfully wait until it is ready to consume more packets,
18173f99db5SVladislav Yaroshchuk * write left ones in temporary buffer and only after this
18273f99db5SVladislav Yaroshchuk * continue reading more packets from vmnet interface.
18373f99db5SVladislav Yaroshchuk *
18473f99db5SVladislav Yaroshchuk * Packets to be transferred are stored into packets_buf,
18573f99db5SVladislav Yaroshchuk * in the window [packets_send_current_pos..packets_send_end_pos)
18673f99db5SVladislav Yaroshchuk * including current_pos, excluding end_pos.
18773f99db5SVladislav Yaroshchuk *
18873f99db5SVladislav Yaroshchuk * Thus, if QEMU is not ready, buffer is not read and
18973f99db5SVladislav Yaroshchuk * packets_send_current_pos < packets_send_end_pos.
19073f99db5SVladislav Yaroshchuk */
19173f99db5SVladislav Yaroshchukstatic void vmnet_send_bh(void *opaque)
19273f99db5SVladislav Yaroshchuk{
19373f99db5SVladislav Yaroshchuk    NetClientState *nc = (NetClientState *) opaque;
19473f99db5SVladislav Yaroshchuk    VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
19573f99db5SVladislav Yaroshchuk
19673f99db5SVladislav Yaroshchuk    /*
19773f99db5SVladislav Yaroshchuk     * Do nothing if QEMU is not ready - wait
19873f99db5SVladislav Yaroshchuk     * for completion callback invocation
19973f99db5SVladislav Yaroshchuk     */
20073f99db5SVladislav Yaroshchuk    if (s->packets_send_current_pos < s->packets_send_end_pos) {
20173f99db5SVladislav Yaroshchuk        return;
20273f99db5SVladislav Yaroshchuk    }
20373f99db5SVladislav Yaroshchuk
20473f99db5SVladislav Yaroshchuk    /* Read packets from vmnet interface */
20573f99db5SVladislav Yaroshchuk    if (vmnet_read_packets(s) > 0) {
20673f99db5SVladislav Yaroshchuk        /* Send them to QEMU */
20773f99db5SVladislav Yaroshchuk        vmnet_write_packets_to_qemu(s);
20873f99db5SVladislav Yaroshchuk    }
20973f99db5SVladislav Yaroshchuk}
21073f99db5SVladislav Yaroshchuk
21173f99db5SVladislav Yaroshchuk
21273f99db5SVladislav Yaroshchuk/**
21373f99db5SVladislav Yaroshchuk * Completion callback to be invoked by QEMU when it becomes
21473f99db5SVladislav Yaroshchuk * ready to consume more packets.
21573f99db5SVladislav Yaroshchuk */
21673f99db5SVladislav Yaroshchukstatic void vmnet_send_completed(NetClientState *nc, ssize_t len)
21773f99db5SVladislav Yaroshchuk{
21873f99db5SVladislav Yaroshchuk    VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
21973f99db5SVladislav Yaroshchuk
22073f99db5SVladislav Yaroshchuk    /* Callback is invoked eq queued packet is sent */
22173f99db5SVladislav Yaroshchuk    ++s->packets_send_current_pos;
22273f99db5SVladislav Yaroshchuk
22373f99db5SVladislav Yaroshchuk    /* Complete sending packets left in VmnetState buffers */
22473f99db5SVladislav Yaroshchuk    vmnet_write_packets_to_qemu(s);
22573f99db5SVladislav Yaroshchuk
22673f99db5SVladislav Yaroshchuk    /* And read new ones from vmnet if VmnetState buffer is ready */
22773f99db5SVladislav Yaroshchuk    if (s->packets_send_current_pos < s->packets_send_end_pos) {
22873f99db5SVladislav Yaroshchuk        qemu_bh_schedule(s->send_bh);
22973f99db5SVladislav Yaroshchuk    }
23073f99db5SVladislav Yaroshchuk}
23173f99db5SVladislav Yaroshchuk
23273f99db5SVladislav Yaroshchuk
23373f99db5SVladislav Yaroshchukstatic void vmnet_bufs_init(VmnetState *s)
23473f99db5SVladislav Yaroshchuk{
23573f99db5SVladislav Yaroshchuk    struct vmpktdesc *packets = s->packets_buf;
23673f99db5SVladislav Yaroshchuk    struct iovec *iov = s->iov_buf;
23773f99db5SVladislav Yaroshchuk    int i;
23873f99db5SVladislav Yaroshchuk
23973f99db5SVladislav Yaroshchuk    for (i = 0; i < VMNET_PACKETS_LIMIT; ++i) {
24073f99db5SVladislav Yaroshchuk        iov[i].iov_len = s->max_packet_size;
24173f99db5SVladislav Yaroshchuk        iov[i].iov_base = g_malloc0(iov[i].iov_len);
24273f99db5SVladislav Yaroshchuk        packets[i].vm_pkt_iov = iov + i;
24373f99db5SVladislav Yaroshchuk    }
24473f99db5SVladislav Yaroshchuk}
24573f99db5SVladislav Yaroshchuk
246993f71eeSJoelle van Dyne/**
247993f71eeSJoelle van Dyne * Called on state change to un-register/re-register handlers
248993f71eeSJoelle van Dyne */
249993f71eeSJoelle van Dynestatic void vmnet_vm_state_change_cb(void *opaque, bool running, RunState state)
250993f71eeSJoelle van Dyne{
251993f71eeSJoelle van Dyne    VmnetState *s = opaque;
252993f71eeSJoelle van Dyne
253993f71eeSJoelle van Dyne    if (running) {
254993f71eeSJoelle van Dyne        vmnet_interface_set_event_callback(
255993f71eeSJoelle van Dyne            s->vmnet_if,
256993f71eeSJoelle van Dyne            VMNET_INTERFACE_PACKETS_AVAILABLE,
257993f71eeSJoelle van Dyne            s->if_queue,
258993f71eeSJoelle van Dyne            ^(interface_event_t event_id, xpc_object_t event) {
259993f71eeSJoelle van Dyne                assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
260993f71eeSJoelle van Dyne                /*
261993f71eeSJoelle van Dyne                 * This function is being called from a non qemu thread, so
262993f71eeSJoelle van Dyne                 * we only schedule a BH, and do the rest of the io completion
263993f71eeSJoelle van Dyne                 * handling from vmnet_send_bh() which runs in a qemu context.
264993f71eeSJoelle van Dyne                 */
265993f71eeSJoelle van Dyne                qemu_bh_schedule(s->send_bh);
266993f71eeSJoelle van Dyne            });
267993f71eeSJoelle van Dyne    } else {
268993f71eeSJoelle van Dyne        vmnet_interface_set_event_callback(
269993f71eeSJoelle van Dyne            s->vmnet_if,
270993f71eeSJoelle van Dyne            VMNET_INTERFACE_PACKETS_AVAILABLE,
271993f71eeSJoelle van Dyne            NULL,
272993f71eeSJoelle van Dyne            NULL);
273993f71eeSJoelle van Dyne    }
274993f71eeSJoelle van Dyne}
27573f99db5SVladislav Yaroshchuk
27673f99db5SVladislav Yaroshchukint vmnet_if_create(NetClientState *nc,
27773f99db5SVladislav Yaroshchuk                    xpc_object_t if_desc,
27873f99db5SVladislav Yaroshchuk                    Error **errp)
27973f99db5SVladislav Yaroshchuk{
28073f99db5SVladislav Yaroshchuk    VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
28173f99db5SVladislav Yaroshchuk    dispatch_semaphore_t if_created_sem = dispatch_semaphore_create(0);
28273f99db5SVladislav Yaroshchuk    __block vmnet_return_t if_status;
28373f99db5SVladislav Yaroshchuk
28473f99db5SVladislav Yaroshchuk    s->if_queue = dispatch_queue_create(
28573f99db5SVladislav Yaroshchuk        "org.qemu.vmnet.if_queue",
28673f99db5SVladislav Yaroshchuk        DISPATCH_QUEUE_SERIAL
28773f99db5SVladislav Yaroshchuk    );
28873f99db5SVladislav Yaroshchuk
28973f99db5SVladislav Yaroshchuk    xpc_dictionary_set_bool(
29073f99db5SVladislav Yaroshchuk        if_desc,
29173f99db5SVladislav Yaroshchuk        vmnet_allocate_mac_address_key,
29273f99db5SVladislav Yaroshchuk        false
29373f99db5SVladislav Yaroshchuk    );
29473f99db5SVladislav Yaroshchuk
29573f99db5SVladislav Yaroshchuk#ifdef DEBUG
29673f99db5SVladislav Yaroshchuk    qemu_log("vmnet.start.interface_desc:\n");
29773f99db5SVladislav Yaroshchuk    xpc_dictionary_apply(if_desc,
29873f99db5SVladislav Yaroshchuk                         ^bool(const char *k, xpc_object_t v) {
29973f99db5SVladislav Yaroshchuk                             char *desc = xpc_copy_description(v);
30073f99db5SVladislav Yaroshchuk                             qemu_log("  %s=%s\n", k, desc);
30173f99db5SVladislav Yaroshchuk                             free(desc);
30273f99db5SVladislav Yaroshchuk                             return true;
30373f99db5SVladislav Yaroshchuk                         });
30473f99db5SVladislav Yaroshchuk#endif /* DEBUG */
30573f99db5SVladislav Yaroshchuk
30673f99db5SVladislav Yaroshchuk    s->vmnet_if = vmnet_start_interface(
30773f99db5SVladislav Yaroshchuk        if_desc,
30873f99db5SVladislav Yaroshchuk        s->if_queue,
30973f99db5SVladislav Yaroshchuk        ^(vmnet_return_t status, xpc_object_t interface_param) {
31073f99db5SVladislav Yaroshchuk            if_status = status;
31173f99db5SVladislav Yaroshchuk            if (status != VMNET_SUCCESS || !interface_param) {
31273f99db5SVladislav Yaroshchuk                dispatch_semaphore_signal(if_created_sem);
31373f99db5SVladislav Yaroshchuk                return;
31473f99db5SVladislav Yaroshchuk            }
31573f99db5SVladislav Yaroshchuk
31673f99db5SVladislav Yaroshchuk#ifdef DEBUG
31773f99db5SVladislav Yaroshchuk            qemu_log("vmnet.start.interface_param:\n");
31873f99db5SVladislav Yaroshchuk            xpc_dictionary_apply(interface_param,
31973f99db5SVladislav Yaroshchuk                                 ^bool(const char *k, xpc_object_t v) {
32073f99db5SVladislav Yaroshchuk                                     char *desc = xpc_copy_description(v);
32173f99db5SVladislav Yaroshchuk                                     qemu_log("  %s=%s\n", k, desc);
32273f99db5SVladislav Yaroshchuk                                     free(desc);
32373f99db5SVladislav Yaroshchuk                                     return true;
32473f99db5SVladislav Yaroshchuk                                 });
32573f99db5SVladislav Yaroshchuk#endif /* DEBUG */
32673f99db5SVladislav Yaroshchuk
32773f99db5SVladislav Yaroshchuk            s->mtu = xpc_dictionary_get_uint64(
32873f99db5SVladislav Yaroshchuk                interface_param,
32973f99db5SVladislav Yaroshchuk                vmnet_mtu_key);
33073f99db5SVladislav Yaroshchuk            s->max_packet_size = xpc_dictionary_get_uint64(
33173f99db5SVladislav Yaroshchuk                interface_param,
33273f99db5SVladislav Yaroshchuk                vmnet_max_packet_size_key);
33373f99db5SVladislav Yaroshchuk
33473f99db5SVladislav Yaroshchuk            dispatch_semaphore_signal(if_created_sem);
33573f99db5SVladislav Yaroshchuk        });
33673f99db5SVladislav Yaroshchuk
33773f99db5SVladislav Yaroshchuk    if (s->vmnet_if == NULL) {
33873f99db5SVladislav Yaroshchuk        dispatch_release(s->if_queue);
33973f99db5SVladislav Yaroshchuk        dispatch_release(if_created_sem);
34073f99db5SVladislav Yaroshchuk        error_setg(errp,
34173f99db5SVladislav Yaroshchuk                   "unable to create interface with requested params");
34273f99db5SVladislav Yaroshchuk        return -1;
34373f99db5SVladislav Yaroshchuk    }
34473f99db5SVladislav Yaroshchuk
34573f99db5SVladislav Yaroshchuk    dispatch_semaphore_wait(if_created_sem, DISPATCH_TIME_FOREVER);
34673f99db5SVladislav Yaroshchuk    dispatch_release(if_created_sem);
34773f99db5SVladislav Yaroshchuk
34873f99db5SVladislav Yaroshchuk    if (if_status != VMNET_SUCCESS) {
34973f99db5SVladislav Yaroshchuk        dispatch_release(s->if_queue);
35073f99db5SVladislav Yaroshchuk        error_setg(errp,
35173f99db5SVladislav Yaroshchuk                   "cannot create vmnet interface: %s",
35273f99db5SVladislav Yaroshchuk                   vmnet_status_map_str(if_status));
35373f99db5SVladislav Yaroshchuk        return -1;
35473f99db5SVladislav Yaroshchuk    }
35573f99db5SVladislav Yaroshchuk
35673f99db5SVladislav Yaroshchuk    s->send_bh = aio_bh_new(qemu_get_aio_context(), vmnet_send_bh, nc);
35773f99db5SVladislav Yaroshchuk    vmnet_bufs_init(s);
35873f99db5SVladislav Yaroshchuk
35973f99db5SVladislav Yaroshchuk    s->packets_send_current_pos = 0;
36073f99db5SVladislav Yaroshchuk    s->packets_send_end_pos = 0;
36173f99db5SVladislav Yaroshchuk
362993f71eeSJoelle van Dyne    vmnet_vm_state_change_cb(s, 1, RUN_STATE_RUNNING);
363993f71eeSJoelle van Dyne
364993f71eeSJoelle van Dyne    s->change = qemu_add_vm_change_state_handler(vmnet_vm_state_change_cb, s);
36573f99db5SVladislav Yaroshchuk
36673f99db5SVladislav Yaroshchuk    return 0;
36773f99db5SVladislav Yaroshchuk}
36873f99db5SVladislav Yaroshchuk
36973f99db5SVladislav Yaroshchuk
37073f99db5SVladislav Yaroshchukvoid vmnet_cleanup_common(NetClientState *nc)
37173f99db5SVladislav Yaroshchuk{
37273f99db5SVladislav Yaroshchuk    VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
37373f99db5SVladislav Yaroshchuk    dispatch_semaphore_t if_stopped_sem;
37473f99db5SVladislav Yaroshchuk
37573f99db5SVladislav Yaroshchuk    if (s->vmnet_if == NULL) {
37673f99db5SVladislav Yaroshchuk        return;
37773f99db5SVladislav Yaroshchuk    }
37873f99db5SVladislav Yaroshchuk
379993f71eeSJoelle van Dyne    vmnet_vm_state_change_cb(s, 0, RUN_STATE_SHUTDOWN);
380993f71eeSJoelle van Dyne    qemu_del_vm_change_state_handler(s->change);
38173f99db5SVladislav Yaroshchuk    if_stopped_sem = dispatch_semaphore_create(0);
38273f99db5SVladislav Yaroshchuk    vmnet_stop_interface(
38373f99db5SVladislav Yaroshchuk        s->vmnet_if,
38473f99db5SVladislav Yaroshchuk        s->if_queue,
38573f99db5SVladislav Yaroshchuk        ^(vmnet_return_t status) {
38673f99db5SVladislav Yaroshchuk            assert(status == VMNET_SUCCESS);
38773f99db5SVladislav Yaroshchuk            dispatch_semaphore_signal(if_stopped_sem);
38873f99db5SVladislav Yaroshchuk        });
38973f99db5SVladislav Yaroshchuk    dispatch_semaphore_wait(if_stopped_sem, DISPATCH_TIME_FOREVER);
39073f99db5SVladislav Yaroshchuk
39173f99db5SVladislav Yaroshchuk    qemu_purge_queued_packets(nc);
39273f99db5SVladislav Yaroshchuk
39373f99db5SVladislav Yaroshchuk    qemu_bh_delete(s->send_bh);
39473f99db5SVladislav Yaroshchuk    dispatch_release(if_stopped_sem);
39573f99db5SVladislav Yaroshchuk    dispatch_release(s->if_queue);
39673f99db5SVladislav Yaroshchuk
39773f99db5SVladislav Yaroshchuk    for (int i = 0; i < VMNET_PACKETS_LIMIT; ++i) {
39873f99db5SVladislav Yaroshchuk        g_free(s->iov_buf[i].iov_base);
39973f99db5SVladislav Yaroshchuk    }
40073f99db5SVladislav Yaroshchuk}
401