HRESULT HostNetworkInterface::i_setVirtualBox(VirtualBox *pVirtualBox)
{
    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AssertReturn(mVirtualBox != pVirtualBox, S_OK);

    unconst(mVirtualBox) = pVirtualBox;

#if !defined(RT_OS_WINDOWS)
    /* If IPv4 address hasn't been initialized */
    if (m.IPAddress == 0 && mIfType == HostNetworkInterfaceType_HostOnly)
    {
        Bstr tmpAddr, tmpMask;
        HRESULT hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
                                                        mInterfaceName.c_str()).raw(),
                                                tmpAddr.asOutParam());
        if (FAILED(hrc) || tmpAddr.isEmpty())
            tmpAddr = getDefaultIPv4Address(mInterfaceName);

        hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
                                                mInterfaceName.c_str()).raw(),
                                        tmpMask.asOutParam());
        if (FAILED(hrc) || tmpMask.isEmpty())
            tmpMask = Bstr(VBOXNET_IPV4MASK_DEFAULT);

        m.IPAddress = inet_addr(Utf8Str(tmpAddr).c_str());
        m.networkMask = inet_addr(Utf8Str(tmpMask).c_str());
    }

    if (m.IPV6Address.isEmpty())
    {
        Bstr bstrIPV4Addr;
        Bstr tmpPrefixLen;
        HRESULT hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
                                                        mInterfaceName.c_str()).raw(),
                                                bstrIPV4Addr.asOutParam());
        if (SUCCEEDED(hrc))
        {
            m.IPV6Address = bstrIPV4Addr;
            if (!m.IPV6Address.isEmpty())
            {
                hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6PrefixLen",
                                                        mInterfaceName.c_str()).raw(),
                                                tmpPrefixLen.asOutParam());
                if (SUCCEEDED(hrc) && !tmpPrefixLen.isEmpty())
                    m.IPV6NetworkMaskPrefixLength = Utf8Str(tmpPrefixLen).toUInt32();
                else
                    m.IPV6NetworkMaskPrefixLength = 64;
            }
        }
    }
#endif

    return S_OK;
}
Example #2
0
/**
 * Sets the Guest Additions version information details.
 *
 * Gets called by vmmdevUpdateGuestInfo2 and vmmdevUpdateGuestInfo (to clear the
 * state).
 *
 * @param   a_uFullVersion          VBoxGuestInfo2::additionsMajor,
 *                                  VBoxGuestInfo2::additionsMinor and
 *                                  VBoxGuestInfo2::additionsBuild combined into
 *                                  one value by VBOX_FULL_VERSION_MAKE.
 *
 *                                  When this is 0, it's vmmdevUpdateGuestInfo
 *                                  calling to reset the state.
 *
 * @param   a_pszName               Build type tag and/or publisher tag, empty
 *                                  string if neiter of those are present.
 * @param   a_uRevision             See VBoxGuestInfo2::additionsRevision.
 * @param   a_fFeatures             See VBoxGuestInfo2::additionsFeatures.
 */
void Guest::setAdditionsInfo2(uint32_t a_uFullVersion, const char *a_pszName, uint32_t a_uRevision, uint32_t a_fFeatures)
{
    AutoCaller autoCaller(this);
    AssertComRCReturnVoid(autoCaller.rc());

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (a_uFullVersion)
    {
        mData.mAdditionsVersionNew  = BstrFmt(*a_pszName ? "%u.%u.%u_%s" : "%u.%u.%u",
                                              VBOX_FULL_VERSION_GET_MAJOR(a_uFullVersion),
                                              VBOX_FULL_VERSION_GET_MINOR(a_uFullVersion),
                                              VBOX_FULL_VERSION_GET_BUILD(a_uFullVersion),
                                              a_pszName);
        mData.mAdditionsVersionFull = a_uFullVersion;
        mData.mAdditionsRevision    = a_uRevision;
        mData.mAdditionsFeatures    = a_fFeatures;
    }
    else
    {
        Assert(!a_fFeatures && !a_uRevision && !*a_pszName);
        mData.mAdditionsVersionNew.setNull();
        mData.mAdditionsVersionFull = 0;
        mData.mAdditionsRevision    = 0;
        mData.mAdditionsFeatures    = 0;
    }
}
Example #3
0
/**
 * @interface_method_impl{PDMIPCIRAWUP,pfnPciDeviceConstructComplete}
 */
DECLCALLBACK(int) PCIRawDev::drvDeviceConstructComplete(PPDMIPCIRAWCONNECTOR pInterface, const char *pcszName,
                                                        uint32_t uHostPCIAddress, uint32_t uGuestPCIAddress,
                                                        int rc)
{
    PDRVMAINPCIRAWDEV pThis = RT_FROM_CPP_MEMBER(pInterface, DRVMAINPCIRAWDEV, IConnector);
    Console *pConsole = pThis->pPCIRawDev->getParent();
    const ComPtr<IMachine>& machine = pConsole->machine();
    ComPtr<IVirtualBox> vbox;

    HRESULT hrc = machine->COMGETTER(Parent)(vbox.asOutParam());
    Assert(SUCCEEDED(hrc));

    ComPtr<IEventSource> es;
    hrc = vbox->COMGETTER(EventSource)(es.asOutParam());
    Assert(SUCCEEDED(hrc));

    Bstr bstrId;
    hrc = machine->COMGETTER(Id)(bstrId.asOutParam());
    Assert(SUCCEEDED(hrc));

    ComObjPtr<PCIDeviceAttachment> pda;
    BstrFmt bstrName(pcszName);
    pda.createObject();
    pda->init(machine, bstrName, uHostPCIAddress, uGuestPCIAddress, TRUE);

    Bstr msg("");
    if (RT_FAILURE(rc))
        msg = BstrFmt("runtime error %Rrc", rc);

    fireHostPCIDevicePlugEvent(es, bstrId.raw(), true /* plugged */, RT_SUCCESS(rc) /* success */, pda, msg.raw());

    return VINF_SUCCESS;
}
HRESULT HostNetworkInterface::enableStaticIPConfigV6(const com::Utf8Str &aIPV6Address,
                                                     ULONG aIPV6NetworkMaskPrefixLength)
{
#ifndef VBOX_WITH_HOSTNETIF_API
    return E_NOTIMPL;
#else
    if (aIPV6NetworkMaskPrefixLength > 128)
        return E_INVALIDARG;

    int rc = S_OK;
    if (   m.realIPV6Address      != aIPV6Address
        || m.realIPV6PrefixLength != aIPV6NetworkMaskPrefixLength)
    {
        BSTR bstr;
        aIPV6Address.cloneTo(&bstr);
        if (aIPV6NetworkMaskPrefixLength == 0)
            aIPV6NetworkMaskPrefixLength = 64;
        rc = NetIfEnableStaticIpConfigV6(mVirtualBox, this, m.IPV6Address.raw(),
                                         bstr, aIPV6NetworkMaskPrefixLength);
        if (RT_FAILURE(rc))
        {
            LogRel(("Failed to EnableStaticIpConfigV6 with rc=%Rrc\n", rc));
            return rc == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
        }
        else
        {
            m.realIPV6Address = aIPV6Address;
            m.realIPV6PrefixLength = aIPV6NetworkMaskPrefixLength;
            if (FAILED(mVirtualBox->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address",
                                                         mInterfaceName.raw()).raw(),
                                                 Bstr(aIPV6Address).raw())))
                return E_FAIL;
            if (FAILED(mVirtualBox->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask",
                                                         mInterfaceName.raw()).raw(),
                                                 BstrFmt("%u", aIPV6NetworkMaskPrefixLength).raw())))
                return E_FAIL;
        }

    }
    return S_OK;
#endif
}
STDMETHODIMP HostNetworkInterface::EnableStaticIpConfigV6 (IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
{
#ifndef VBOX_WITH_HOSTNETIF_API
    return E_NOTIMPL;
#else
    if (!aIPV6Address)
        return E_INVALIDARG;
    if (aIPV6MaskPrefixLength > 128)
        return E_INVALIDARG;

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    int rc = S_OK;
    if (m.realIPV6Address != aIPV6Address || m.realIPV6PrefixLength != aIPV6MaskPrefixLength)
    {
        if (aIPV6MaskPrefixLength == 0)
            aIPV6MaskPrefixLength = 64;
        rc = NetIfEnableStaticIpConfigV6(mVBox, this, m.IPV6Address.raw(), aIPV6Address, aIPV6MaskPrefixLength);
        if (RT_FAILURE(rc))
        {
            LogRel(("Failed to EnableStaticIpConfigV6 with rc=%Rrc\n", rc));
            return rc == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
        }
        else
        {
            m.realIPV6Address = aIPV6Address;
            m.realIPV6PrefixLength = aIPV6MaskPrefixLength;
            if (FAILED(mVBox->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", mInterfaceName.raw()).raw(),
                                           Bstr(aIPV6Address).raw())))
                return E_FAIL;
            if (FAILED(mVBox->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", mInterfaceName.raw()).raw(),
                                           BstrFmt("%u", aIPV6MaskPrefixLength).raw())))
                return E_FAIL;
        }

    }
    return S_OK;
#endif
}
Example #6
0
/**
 * Sets the Guest Additions version information details.
 * Gets called by vmmdevUpdateGuestInfo2.
 *
 * @param aAdditionsVersion
 * @param aVersionName
 */
void Guest::setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision)
{
    AutoCaller autoCaller(this);
    AssertComRCReturnVoid(autoCaller.rc());

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (!aVersionName.isEmpty())
        /*
         * aVersionName could be "x.y.z_BETA1_FOOBAR", so append revision manually to
         * become "x.y.z_BETA1_FOOBAR r12345".
         */
        mData.mAdditionsVersion = BstrFmt("%ls r%ls", aVersionName.raw(), aRevision.raw());
    else /* aAdditionsVersion is in x.y.zr12345 format. */
        mData.mAdditionsVersion = aAdditionsVersion;
}
STDMETHODIMP VFSExplorer::Update(IProgress **aProgress)
{
    CheckComArgOutPointerValid(aProgress);

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    HRESULT rc = S_OK;

    ComObjPtr<Progress> progress;
    try
    {
        Bstr progressDesc = BstrFmt(tr("Update directory info for '%s'"),
                                    m->strPath.c_str());
        /* Create the progress object */
        progress.createObject();

        rc = progress->init(mVirtualBox,
                            static_cast<IVFSExplorer*>(this),
                            progressDesc.raw(),
                            TRUE /* aCancelable */);
        if (FAILED(rc)) throw rc;

        /* Initialize our worker task */
        std::auto_ptr<TaskVFSExplorer> task(new TaskVFSExplorer(TaskVFSExplorer::Update, this, progress));

        rc = task->startThread();
        if (FAILED(rc)) throw rc;

        /* Don't destruct on success */
        task.release();
    }
    catch (HRESULT aRC)
    {
        rc = aRC;
    }

    if (SUCCEEDED(rc))
        /* Return progress to the caller */
        progress.queryInterfaceTo(aProgress);

    return rc;
}
HRESULT HostNetworkInterface::enableStaticIPConfig(const com::Utf8Str &aIPAddress,
                                                   const com::Utf8Str &aNetworkMask)
{
#ifndef VBOX_WITH_HOSTNETIF_API
    return E_NOTIMPL;
#else
    if (aIPAddress.isEmpty())
    {
        if (m.IPAddress)
        {
            int rc = NetIfEnableStaticIpConfig(mVirtualBox, this, m.IPAddress, 0, 0);
            if (RT_SUCCESS(rc))
            {
                m.realIPAddress = 0;
                if (FAILED(mVirtualBox->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
                                                             mInterfaceName.raw()).raw(), NULL)))
                    return E_FAIL;
                if (FAILED(mVirtualBox->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
                                                             mInterfaceName.raw()).raw(), NULL)))
                    return E_FAIL;
                return S_OK;
            }
        }
        else
            return S_OK;
    }

    ULONG ip, mask;
    ip = inet_addr(aIPAddress.c_str());
    if (ip != INADDR_NONE)
    {
        if (aNetworkMask.isEmpty())
            mask = 0xFFFFFF;
        else
            mask = inet_addr(aNetworkMask.c_str());
        if (mask != INADDR_NONE)
        {
            if (m.realIPAddress == ip && m.realNetworkMask == mask)
                return S_OK;
            int rc = NetIfEnableStaticIpConfig(mVirtualBox, this, m.IPAddress, ip, mask);
            if (RT_SUCCESS(rc))
            {
                m.realIPAddress   = ip;
                m.realNetworkMask = mask;
                if (FAILED(mVirtualBox->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
                                                             mInterfaceName.raw()).raw(),
                                                     Bstr(aIPAddress).raw())))
                    return E_FAIL;
                if (FAILED(mVirtualBox->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
                                                             mInterfaceName.raw()).raw(),
                                                     Bstr(aNetworkMask).raw())))
                    return E_FAIL;
                return S_OK;
            }
            else
            {
                LogRel(("Failed to EnableStaticIpConfig with rc=%Rrc\n", rc));
                return rc == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
            }

        }
    }
    return E_FAIL;
#endif
}
Example #9
0
STDMETHODIMP Guest::COMGETTER(AdditionsVersion) (BSTR *aAdditionsVersion)
{
    CheckComArgOutPointerValid(aAdditionsVersion);

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    HRESULT hr = S_OK;
    if (   mData.mAdditionsVersion.isEmpty()
        /* Only try alternative way if GA are active! */
        && mData.mAdditionsRunLevel > AdditionsRunLevelType_None)
    {
        /*
         * If we got back an empty string from GetAdditionsVersion() we either
         * really don't have the Guest Additions version yet or the guest is running
         * older Guest Additions (< 3.2.0) which don't provide VMMDevReq_ReportGuestInfo2,
         * so get the version + revision from the (hopefully) provided guest properties
         * instead.
         */
        Bstr addVersion;
        LONG64 u64Timestamp;
        Bstr flags;
        hr = mParent->machine()->GetGuestProperty(Bstr("/VirtualBox/GuestAdd/Version").raw(),
                                                  addVersion.asOutParam(), &u64Timestamp, flags.asOutParam());
        if (hr == S_OK)
        {
            Bstr addRevision;
            hr = mParent->machine()->GetGuestProperty(Bstr("/VirtualBox/GuestAdd/Revision").raw(),
                                                      addRevision.asOutParam(), &u64Timestamp, flags.asOutParam());
            if (   hr == S_OK
                && !addVersion.isEmpty()
                && !addRevision.isEmpty())
            {
                /* Some Guest Additions versions had interchanged version + revision values,
                 * so check if the version value at least has a dot to identify it and change
                 * both values to reflect the right content. */
                if (!Utf8Str(addVersion).contains("."))
                {
                    Bstr addTemp = addVersion;
                    addVersion = addRevision;
                    addRevision = addTemp;
                }

                Bstr additionsVersion = BstrFmt("%ls r%ls",
                                                addVersion.raw(), addRevision.raw());
                additionsVersion.cloneTo(aAdditionsVersion);
            }
            /** @todo r=bird: else: Should not return failure! */
        }
        else
        {
            /* If getting the version + revision above fails or they simply aren't there
             * because of *really* old Guest Additions we only can report the interface
             * version to at least have something. */
            mData.mInterfaceVersion.cloneTo(aAdditionsVersion);
            /** @todo r=bird: hr is still indicating failure! */
        }
    }
    else
        mData.mAdditionsVersion.cloneTo(aAdditionsVersion);

    return hr;
}
Console::teleporterTrgServeConnection(RTSOCKET Sock, void *pvUser)
{
    TeleporterStateTrg *pState = (TeleporterStateTrg *)pvUser;
    pState->mhSocket = Sock;

    /*
     * Disable Nagle and say hello.
     */
    int vrc = RTTcpSetSendCoalescing(pState->mhSocket, false /*fEnable*/);
    AssertRC(vrc);
    vrc = RTTcpWrite(Sock, g_szWelcome, sizeof(g_szWelcome) - 1);
    if (RT_FAILURE(vrc))
    {
        LogRel(("Teleporter: Failed to write welcome message: %Rrc\n", vrc));
        return VINF_SUCCESS;
    }

    /*
     * Password (includes '\n', see teleporterTrg).
     */
    const char *pszPassword = pState->mstrPassword.c_str();
    unsigned    off = 0;
    while (pszPassword[off])
    {
        char ch;
        vrc = RTTcpRead(Sock, &ch, sizeof(ch), NULL);
        if (    RT_FAILURE(vrc)
                ||  pszPassword[off] != ch)
        {
            if (RT_FAILURE(vrc))
                LogRel(("Teleporter: Password read failure (off=%u): %Rrc\n", off, vrc));
            else
                LogRel(("Teleporter: Invalid password (off=%u)\n", off));
            teleporterTcpWriteNACK(pState, VERR_AUTHENTICATION_FAILURE);
            return VINF_SUCCESS;
        }
        off++;
    }
    vrc = teleporterTcpWriteACK(pState);
    if (RT_FAILURE(vrc))
        return VINF_SUCCESS;

    /*
     * Update the progress bar, with peer name if available.
     */
    HRESULT     hrc;
    RTNETADDR   Addr;
    vrc = RTTcpGetPeerAddress(Sock, &Addr);
    if (RT_SUCCESS(vrc))
    {
        LogRel(("Teleporter: Incoming VM from %RTnaddr!\n", &Addr));
        hrc = pState->mptrProgress->SetNextOperation(BstrFmt(tr("Teleporting VM from %RTnaddr"), &Addr).raw(), 8);
    }
    else
    {
        LogRel(("Teleporter: Incoming VM!\n"));
        hrc = pState->mptrProgress->SetNextOperation(Bstr(tr("Teleporting VM")).raw(), 8);
    }
    AssertMsg(SUCCEEDED(hrc) || hrc == E_FAIL, ("%Rhrc\n", hrc));

    /*
     * Stop the server and cancel the timeout timer.
     *
     * Note! After this point we must return VERR_TCP_SERVER_STOP, while prior
     *       to it we must not return that value!
     */
    RTTcpServerShutdown(pState->mhServer);
    RTTimerLRDestroy(*pState->mphTimerLR);
    *pState->mphTimerLR = NIL_RTTIMERLR;

    /*
     * Command processing loop.
     */
    bool fDone = false;
    for (;;)
    {
        char szCmd[128];
        vrc = teleporterTcpReadLine(pState, szCmd, sizeof(szCmd));
        if (RT_FAILURE(vrc))
            break;

        if (!strcmp(szCmd, "load"))
        {
            vrc = teleporterTcpWriteACK(pState);
            if (RT_FAILURE(vrc))
                break;

            int vrc2 = VMR3AtErrorRegisterU(pState->mpUVM,
                                            Console::genericVMSetErrorCallback, &pState->mErrorText);
            AssertRC(vrc2);
            RTSocketRetain(pState->mhSocket); /* For concurrent access by I/O thread and EMT. */
            pState->moffStream = 0;

            void *pvUser2 = static_cast<void *>(static_cast<TeleporterState *>(pState));
            vrc = VMR3LoadFromStream(VMR3GetVM(pState->mpUVM),
                                     &g_teleporterTcpOps, pvUser2,
                                     teleporterProgressCallback, pvUser2);

            RTSocketRelease(pState->mhSocket);
            vrc2 = VMR3AtErrorDeregister(VMR3GetVM(pState->mpUVM), Console::genericVMSetErrorCallback, &pState->mErrorText);
            AssertRC(vrc2);

            if (RT_FAILURE(vrc))
            {
                LogRel(("Teleporter: VMR3LoadFromStream -> %Rrc\n", vrc));
                teleporterTcpWriteNACK(pState, vrc, pState->mErrorText.c_str());
                break;
            }

            /* The EOS might not have been read, make sure it is. */
            pState->mfStopReading = false;
            size_t cbRead;
            vrc = teleporterTcpOpRead(pvUser2, pState->moffStream, szCmd, 1, &cbRead);
            if (vrc != VERR_EOF)
            {
                LogRel(("Teleporter: Draining teleporterTcpOpRead -> %Rrc\n", vrc));
                teleporterTcpWriteNACK(pState, vrc);
                break;
            }

            vrc = teleporterTcpWriteACK(pState);
        }
        else if (!strcmp(szCmd, "cancel"))
        {
            /* Don't ACK this. */
            LogRel(("Teleporter: Received cancel command.\n"));
            vrc = VERR_SSM_CANCELLED;
        }
        else if (!strcmp(szCmd, "lock-media"))
        {
            hrc = pState->mpControl->LockMedia();
            if (SUCCEEDED(hrc))
            {
                pState->mfLockedMedia = true;
                vrc = teleporterTcpWriteACK(pState);
            }
            else
            {
                vrc = VERR_FILE_LOCK_FAILED;
                teleporterTcpWriteNACK(pState, vrc);
            }
        }
        else if (   !strcmp(szCmd, "hand-over-resume")
                    || !strcmp(szCmd, "hand-over-paused"))
        {
            /*
             * Point of no return.
             *
             * Note! Since we cannot tell whether a VMR3Resume failure is
             *       destructive for the source or not, we have little choice
             *       but to ACK it first and take any failures locally.
             *
             *       Ideally, we should try resume it first and then ACK (or
             *       NACK) the request since this would reduce latency and
             *       make it possible to recover from some VMR3Resume failures.
             */
            if (   pState->mptrProgress->notifyPointOfNoReturn()
                    && pState->mfLockedMedia)
            {
                vrc = teleporterTcpWriteACK(pState);
                if (RT_SUCCESS(vrc))
                {
                    if (!strcmp(szCmd, "hand-over-resume"))
                        vrc = VMR3Resume(VMR3GetVM(pState->mpUVM));
                    else
                        pState->mptrConsole->setMachineState(MachineState_Paused);
                    fDone = true;
                    break;
                }
            }
            else
            {
                vrc = pState->mfLockedMedia ? VERR_WRONG_ORDER : VERR_SSM_CANCELLED;
                teleporterTcpWriteNACK(pState, vrc);
            }
        }
        else
        {
            LogRel(("Teleporter: Unknown command '%s' (%.*Rhxs)\n", szCmd, strlen(szCmd), szCmd));
            vrc = VERR_NOT_IMPLEMENTED;
            teleporterTcpWriteNACK(pState, vrc);
        }

        if (RT_FAILURE(vrc))
            break;
    }

    if (RT_SUCCESS(vrc) && !fDone)
        vrc = VERR_WRONG_ORDER;
    if (RT_FAILURE(vrc))
        teleporterTrgUnlockMedia(pState);

    pState->mRc = vrc;
    pState->mhSocket = NIL_RTSOCKET;
    LogFlowFunc(("returns mRc=%Rrc\n", vrc));
    return VERR_TCP_SERVER_STOP;
}
HRESULT HostNetworkInterface::enableStaticIPConfigV6(const com::Utf8Str &aIPV6Address,
                                                     ULONG aIPV6NetworkMaskPrefixLength)
{
#ifndef VBOX_WITH_HOSTNETIF_API
    return E_NOTIMPL;
#else
    if (aIPV6NetworkMaskPrefixLength > 128)
        return mVirtualBox->setErrorBoth(E_INVALIDARG, VERR_INVALID_PARAMETER,
                   "Invalid IPv6 prefix length");

    int rc;

    RTNETADDRIPV6 AddrOld, AddrNew;
    char *pszZoneIgnored;
    bool fAddrChanged;

    rc = RTNetStrToIPv6Addr(aIPV6Address.c_str(), &AddrNew, &pszZoneIgnored);
    if (RT_FAILURE(rc))
    {
        return mVirtualBox->setErrorBoth(E_INVALIDARG, rc, "Invalid IPv6 address");
    }

    rc = RTNetStrToIPv6Addr(com::Utf8Str(m.realIPV6Address).c_str(), &AddrOld, &pszZoneIgnored);
    if (RT_SUCCESS(rc))
    {
        fAddrChanged = (AddrNew.s.Lo != AddrOld.s.Lo || AddrNew.s.Hi != AddrOld.s.Hi);
    }
    else
    {
        fAddrChanged = true;
    }

    if (   fAddrChanged
        || m.realIPV6PrefixLength != aIPV6NetworkMaskPrefixLength)
    {
        if (aIPV6NetworkMaskPrefixLength == 0)
            aIPV6NetworkMaskPrefixLength = 64;
        rc = NetIfEnableStaticIpConfigV6(mVirtualBox, this, m.IPV6Address.c_str(),
                                         aIPV6Address.c_str(),
                                         aIPV6NetworkMaskPrefixLength);
        if (RT_FAILURE(rc))
        {
            LogRel(("Failed to EnableStaticIpConfigV6 with rc=%Rrc\n", rc));
            return rc == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
        }
        else
        {
            m.realIPV6Address = aIPV6Address;
            m.realIPV6PrefixLength = aIPV6NetworkMaskPrefixLength;
#if defined(RT_OS_WINDOWS)
            saveAdapterConfigIPv6(Bstr(aIPV6Address).raw(), aIPV6NetworkMaskPrefixLength);
#else /* !defined(RT_OS_WINDOWS) */
            if (FAILED(mVirtualBox->SetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
                                                         mInterfaceName.c_str()).raw(),
                                                 Bstr(aIPV6Address).raw())))
                return E_FAIL;
            if (FAILED(mVirtualBox->SetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask",
                                                         mInterfaceName.c_str()).raw(),
                                                 BstrFmt("%u", aIPV6NetworkMaskPrefixLength).raw())))
#endif /* !defined(RT_OS_WINDOWS) */
                return E_FAIL;
        }

    }
    return S_OK;
#endif
}