181ad2964SVladislav Yaroshchuk/* 281ad2964SVladislav Yaroshchuk * vmnet-bridged.m 381ad2964SVladislav Yaroshchuk * 481ad2964SVladislav Yaroshchuk * Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> 581ad2964SVladislav Yaroshchuk * 681ad2964SVladislav Yaroshchuk * This work is licensed under the terms of the GNU GPL, version 2 or later. 781ad2964SVladislav Yaroshchuk * See the COPYING file in the top-level directory. 881ad2964SVladislav Yaroshchuk * 981ad2964SVladislav Yaroshchuk */ 1081ad2964SVladislav Yaroshchuk 1181ad2964SVladislav Yaroshchuk#include "qemu/osdep.h" 1281ad2964SVladislav Yaroshchuk#include "qapi/qapi-types-net.h" 1381ad2964SVladislav Yaroshchuk#include "qapi/error.h" 142c313ae2SVladislav Yaroshchuk#include "clients.h" 152c313ae2SVladislav Yaroshchuk#include "vmnet_int.h" 1681ad2964SVladislav Yaroshchuk 1781ad2964SVladislav Yaroshchuk#include <vmnet/vmnet.h> 1881ad2964SVladislav Yaroshchuk 192c313ae2SVladislav Yaroshchuk 202c313ae2SVladislav Yaroshchukstatic bool validate_ifname(const char *ifname) 212c313ae2SVladislav Yaroshchuk{ 222c313ae2SVladislav Yaroshchuk xpc_object_t shared_if_list = vmnet_copy_shared_interface_list(); 232c313ae2SVladislav Yaroshchuk bool match = false; 242c313ae2SVladislav Yaroshchuk if (!xpc_array_get_count(shared_if_list)) { 252c313ae2SVladislav Yaroshchuk goto done; 262c313ae2SVladislav Yaroshchuk } 272c313ae2SVladislav Yaroshchuk 282c313ae2SVladislav Yaroshchuk match = !xpc_array_apply( 292c313ae2SVladislav Yaroshchuk shared_if_list, 302c313ae2SVladislav Yaroshchuk ^bool(size_t index, xpc_object_t value) { 312c313ae2SVladislav Yaroshchuk return strcmp(xpc_string_get_string_ptr(value), ifname) != 0; 322c313ae2SVladislav Yaroshchuk }); 332c313ae2SVladislav Yaroshchuk 342c313ae2SVladislav Yaroshchukdone: 352c313ae2SVladislav Yaroshchuk xpc_release(shared_if_list); 362c313ae2SVladislav Yaroshchuk return match; 372c313ae2SVladislav Yaroshchuk} 382c313ae2SVladislav Yaroshchuk 392c313ae2SVladislav Yaroshchuk 40f975033dSPhilippe Mathieu-Daudéstatic char* get_valid_ifnames(void) 412c313ae2SVladislav Yaroshchuk{ 422c313ae2SVladislav Yaroshchuk xpc_object_t shared_if_list = vmnet_copy_shared_interface_list(); 432c313ae2SVladislav Yaroshchuk __block char *if_list = NULL; 442c313ae2SVladislav Yaroshchuk __block char *if_list_prev = NULL; 452c313ae2SVladislav Yaroshchuk 462c313ae2SVladislav Yaroshchuk if (!xpc_array_get_count(shared_if_list)) { 472c313ae2SVladislav Yaroshchuk goto done; 482c313ae2SVladislav Yaroshchuk } 492c313ae2SVladislav Yaroshchuk 502c313ae2SVladislav Yaroshchuk xpc_array_apply( 512c313ae2SVladislav Yaroshchuk shared_if_list, 522c313ae2SVladislav Yaroshchuk ^bool(size_t index, xpc_object_t value) { 532c313ae2SVladislav Yaroshchuk /* build list of strings like "en0 en1 en2 " */ 542c313ae2SVladislav Yaroshchuk if_list = g_strconcat(xpc_string_get_string_ptr(value), 552c313ae2SVladislav Yaroshchuk " ", 562c313ae2SVladislav Yaroshchuk if_list_prev, 572c313ae2SVladislav Yaroshchuk NULL); 582c313ae2SVladislav Yaroshchuk g_free(if_list_prev); 592c313ae2SVladislav Yaroshchuk if_list_prev = if_list; 602c313ae2SVladislav Yaroshchuk return true; 612c313ae2SVladislav Yaroshchuk }); 622c313ae2SVladislav Yaroshchuk 632c313ae2SVladislav Yaroshchukdone: 642c313ae2SVladislav Yaroshchuk xpc_release(shared_if_list); 652c313ae2SVladislav Yaroshchuk return if_list; 662c313ae2SVladislav Yaroshchuk} 672c313ae2SVladislav Yaroshchuk 682c313ae2SVladislav Yaroshchuk 692c313ae2SVladislav Yaroshchukstatic bool validate_options(const Netdev *netdev, Error **errp) 702c313ae2SVladislav Yaroshchuk{ 712c313ae2SVladislav Yaroshchuk const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged); 722c313ae2SVladislav Yaroshchuk char* if_list; 732c313ae2SVladislav Yaroshchuk 742c313ae2SVladislav Yaroshchuk if (!validate_ifname(options->ifname)) { 752c313ae2SVladislav Yaroshchuk if_list = get_valid_ifnames(); 762c313ae2SVladislav Yaroshchuk if (if_list) { 772c313ae2SVladislav Yaroshchuk error_setg(errp, 782c313ae2SVladislav Yaroshchuk "unsupported ifname '%s', expected one of [ %s]", 792c313ae2SVladislav Yaroshchuk options->ifname, 802c313ae2SVladislav Yaroshchuk if_list); 812c313ae2SVladislav Yaroshchuk g_free(if_list); 822c313ae2SVladislav Yaroshchuk } else { 832c313ae2SVladislav Yaroshchuk error_setg(errp, 842c313ae2SVladislav Yaroshchuk "unsupported ifname '%s', no supported " 852c313ae2SVladislav Yaroshchuk "interfaces available", 862c313ae2SVladislav Yaroshchuk options->ifname); 872c313ae2SVladislav Yaroshchuk } 882c313ae2SVladislav Yaroshchuk return false; 892c313ae2SVladislav Yaroshchuk } 902c313ae2SVladislav Yaroshchuk 912c313ae2SVladislav Yaroshchuk return true; 922c313ae2SVladislav Yaroshchuk} 932c313ae2SVladislav Yaroshchuk 942c313ae2SVladislav Yaroshchuk 952c313ae2SVladislav Yaroshchukstatic xpc_object_t build_if_desc(const Netdev *netdev) 962c313ae2SVladislav Yaroshchuk{ 972c313ae2SVladislav Yaroshchuk const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged); 982c313ae2SVladislav Yaroshchuk xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); 992c313ae2SVladislav Yaroshchuk 1002c313ae2SVladislav Yaroshchuk xpc_dictionary_set_uint64(if_desc, 1012c313ae2SVladislav Yaroshchuk vmnet_operation_mode_key, 1022c313ae2SVladislav Yaroshchuk VMNET_BRIDGED_MODE 1032c313ae2SVladislav Yaroshchuk ); 1042c313ae2SVladislav Yaroshchuk 1052c313ae2SVladislav Yaroshchuk xpc_dictionary_set_string(if_desc, 1062c313ae2SVladislav Yaroshchuk vmnet_shared_interface_name_key, 1072c313ae2SVladislav Yaroshchuk options->ifname); 1082c313ae2SVladislav Yaroshchuk 1092c313ae2SVladislav Yaroshchuk xpc_dictionary_set_bool(if_desc, 1102c313ae2SVladislav Yaroshchuk vmnet_enable_isolation_key, 1112c313ae2SVladislav Yaroshchuk options->isolated); 112*3bf445fbSAkihiko Odaki 1132c313ae2SVladislav Yaroshchuk return if_desc; 1142c313ae2SVladislav Yaroshchuk} 1152c313ae2SVladislav Yaroshchuk 1162c313ae2SVladislav Yaroshchuk 1172c313ae2SVladislav Yaroshchukstatic NetClientInfo net_vmnet_bridged_info = { 1182c313ae2SVladislav Yaroshchuk .type = NET_CLIENT_DRIVER_VMNET_BRIDGED, 1192c313ae2SVladislav Yaroshchuk .size = sizeof(VmnetState), 1202c313ae2SVladislav Yaroshchuk .receive = vmnet_receive_common, 1212c313ae2SVladislav Yaroshchuk .cleanup = vmnet_cleanup_common, 1222c313ae2SVladislav Yaroshchuk}; 1232c313ae2SVladislav Yaroshchuk 1242c313ae2SVladislav Yaroshchuk 12581ad2964SVladislav Yaroshchukint net_init_vmnet_bridged(const Netdev *netdev, const char *name, 12681ad2964SVladislav Yaroshchuk NetClientState *peer, Error **errp) 12781ad2964SVladislav Yaroshchuk{ 1282c313ae2SVladislav Yaroshchuk NetClientState *nc = qemu_new_net_client(&net_vmnet_bridged_info, 1292c313ae2SVladislav Yaroshchuk peer, "vmnet-bridged", name); 1302c313ae2SVladislav Yaroshchuk xpc_object_t if_desc; 1312c313ae2SVladislav Yaroshchuk int result = -1; 1322c313ae2SVladislav Yaroshchuk 1332c313ae2SVladislav Yaroshchuk if (!validate_options(netdev, errp)) { 1342c313ae2SVladislav Yaroshchuk return result; 1352c313ae2SVladislav Yaroshchuk } 1362c313ae2SVladislav Yaroshchuk 1372c313ae2SVladislav Yaroshchuk if_desc = build_if_desc(netdev); 1382c313ae2SVladislav Yaroshchuk result = vmnet_if_create(nc, if_desc, errp); 1392c313ae2SVladislav Yaroshchuk xpc_release(if_desc); 1402c313ae2SVladislav Yaroshchuk return result; 14181ad2964SVladislav Yaroshchuk} 142