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