xref: /qemu/net/vmnet-bridged.m (revision f975033d)
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#if !defined(MAC_OS_VERSION_11_0) || \
922c313ae2SVladislav Yaroshchuk    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
932c313ae2SVladislav Yaroshchuk    if (options->has_isolated) {
942c313ae2SVladislav Yaroshchuk        error_setg(errp,
952c313ae2SVladislav Yaroshchuk                   "vmnet-bridged.isolated feature is "
962c313ae2SVladislav Yaroshchuk                   "unavailable: outdated vmnet.framework API");
972c313ae2SVladislav Yaroshchuk        return false;
982c313ae2SVladislav Yaroshchuk    }
992c313ae2SVladislav Yaroshchuk#endif
1002c313ae2SVladislav Yaroshchuk    return true;
1012c313ae2SVladislav Yaroshchuk}
1022c313ae2SVladislav Yaroshchuk
1032c313ae2SVladislav Yaroshchuk
1042c313ae2SVladislav Yaroshchukstatic xpc_object_t build_if_desc(const Netdev *netdev)
1052c313ae2SVladislav Yaroshchuk{
1062c313ae2SVladislav Yaroshchuk    const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
1072c313ae2SVladislav Yaroshchuk    xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
1082c313ae2SVladislav Yaroshchuk
1092c313ae2SVladislav Yaroshchuk    xpc_dictionary_set_uint64(if_desc,
1102c313ae2SVladislav Yaroshchuk                              vmnet_operation_mode_key,
1112c313ae2SVladislav Yaroshchuk                              VMNET_BRIDGED_MODE
1122c313ae2SVladislav Yaroshchuk    );
1132c313ae2SVladislav Yaroshchuk
1142c313ae2SVladislav Yaroshchuk    xpc_dictionary_set_string(if_desc,
1152c313ae2SVladislav Yaroshchuk                              vmnet_shared_interface_name_key,
1162c313ae2SVladislav Yaroshchuk                              options->ifname);
1172c313ae2SVladislav Yaroshchuk
1182c313ae2SVladislav Yaroshchuk#if defined(MAC_OS_VERSION_11_0) && \
1192c313ae2SVladislav Yaroshchuk    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
1202c313ae2SVladislav Yaroshchuk    xpc_dictionary_set_bool(if_desc,
1212c313ae2SVladislav Yaroshchuk                            vmnet_enable_isolation_key,
1222c313ae2SVladislav Yaroshchuk                            options->isolated);
1232c313ae2SVladislav Yaroshchuk#endif
1242c313ae2SVladislav Yaroshchuk    return if_desc;
1252c313ae2SVladislav Yaroshchuk}
1262c313ae2SVladislav Yaroshchuk
1272c313ae2SVladislav Yaroshchuk
1282c313ae2SVladislav Yaroshchukstatic NetClientInfo net_vmnet_bridged_info = {
1292c313ae2SVladislav Yaroshchuk    .type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
1302c313ae2SVladislav Yaroshchuk    .size = sizeof(VmnetState),
1312c313ae2SVladislav Yaroshchuk    .receive = vmnet_receive_common,
1322c313ae2SVladislav Yaroshchuk    .cleanup = vmnet_cleanup_common,
1332c313ae2SVladislav Yaroshchuk};
1342c313ae2SVladislav Yaroshchuk
1352c313ae2SVladislav Yaroshchuk
13681ad2964SVladislav Yaroshchukint net_init_vmnet_bridged(const Netdev *netdev, const char *name,
13781ad2964SVladislav Yaroshchuk                           NetClientState *peer, Error **errp)
13881ad2964SVladislav Yaroshchuk{
1392c313ae2SVladislav Yaroshchuk    NetClientState *nc = qemu_new_net_client(&net_vmnet_bridged_info,
1402c313ae2SVladislav Yaroshchuk                                             peer, "vmnet-bridged", name);
1412c313ae2SVladislav Yaroshchuk    xpc_object_t if_desc;
1422c313ae2SVladislav Yaroshchuk    int result = -1;
1432c313ae2SVladislav Yaroshchuk
1442c313ae2SVladislav Yaroshchuk    if (!validate_options(netdev, errp)) {
1452c313ae2SVladislav Yaroshchuk        return result;
1462c313ae2SVladislav Yaroshchuk    }
1472c313ae2SVladislav Yaroshchuk
1482c313ae2SVladislav Yaroshchuk    if_desc = build_if_desc(netdev);
1492c313ae2SVladislav Yaroshchuk    result = vmnet_if_create(nc, if_desc, errp);
1502c313ae2SVladislav Yaroshchuk    xpc_release(if_desc);
1512c313ae2SVladislav Yaroshchuk    return result;
15281ad2964SVladislav Yaroshchuk}
153