[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH 8/8] Add functions to backup and restore network settings



In PdoStartDevice(), if an aliasing emulated device is found in the MIB
interface table, back up its network settings to a private area under the
the PDO software key before requesting reboot.

In a later boot, if the emulated device has been unplugged, restore the
network settings from the private area to the PDO such that it will start
with the same configuration as the emulated device it has replaced.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 src/xenvif/pdo.c             |  91 +++++++-
 src/xenvif/settings.c        | 495 +++++++++++++++++++++++++++++++++++++++++++
 src/xenvif/settings.h        |  53 +++++
 vs2012/xenvif/xenvif.vcxproj |   1 +
 vs2013/xenvif/xenvif.vcxproj |   1 +
 5 files changed, 637 insertions(+), 4 deletions(-)
 create mode 100644 src/xenvif/settings.c
 create mode 100644 src/xenvif/settings.h

diff --git a/src/xenvif/pdo.c b/src/xenvif/pdo.c
index 140b618..8b6fbd4 100644
--- a/src/xenvif/pdo.c
+++ b/src/xenvif/pdo.c
@@ -53,6 +53,7 @@
 #include "registry.h"
 #include "thread.h"
 #include "link.h"
+#include "settings.h"
 #include "dbg_print.h"
 #include "assert.h"
 #include "util.h"
@@ -1071,6 +1072,51 @@ PdoS3ToS4(
     Trace("(%s) <====\n", __PdoGetName(Pdo));
 }
 
+static NTSTATUS
+PdoGetInterfaceGuid(
+    IN  PXENVIF_PDO Pdo,
+    IN  HANDLE      Key,
+    OUT LPGUID      Guid
+    )
+{
+    PANSI_STRING    Ansi;
+    UNICODE_STRING  Unicode;
+    NTSTATUS        status;
+
+    UNREFERENCED_PARAMETER(Pdo);
+
+    status = RegistryQuerySzValue(Key,
+                                  "NetCfgInstanceId",
+                                  &Ansi);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi[0], TRUE);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = RtlGUIDFromString(&Unicode, Guid);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+    RtlFreeUnicodeString(&Unicode);
+
+fail2:
+    Error("fail2\n");
+
+    RegistryFreeSzValue(Ansi);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
 static DECLSPEC_NOINLINE NTSTATUS
 PdoStartDevice(
     IN  PXENVIF_PDO     Pdo,
@@ -1081,8 +1127,10 @@ PdoStartDevice(
     VOID                (*__FreeMibTable)(PVOID);
     PMIB_IF_TABLE2      Table;
     ULONG               Index;
+    PMIB_IF_ROW2        Row;
     PIO_STACK_LOCATION  StackLocation;
     HANDLE              Key;
+    GUID                Guid;
     NTSTATUS            status;
 
     status = STATUS_UNSUCCESSFUL;
@@ -1115,8 +1163,13 @@ PdoStartDevice(
     if (!NT_SUCCESS(status))
         goto fail6;
 
+    //
+    // Look for a network interface with the same permanent address
+    // that is already up. If there is one then it must be an
+    // aliasing emulated device, so save its settings.
+    //
     for (Index = 0; Index < Table->NumEntries; Index++) {
-        PMIB_IF_ROW2    Row = &Table->Table[Index];
+        Row = &Table->Table[Index];
 
         if (!(Row->InterfaceAndOperStatusFlags.HardwareInterface) ||
             !(Row->InterfaceAndOperStatusFlags.ConnectorPresent))
@@ -1128,11 +1181,34 @@ PdoStartDevice(
         if (Row->PhysicalAddressLength != sizeof (ETHERNET_ADDRESS))
             continue;
 
-        status = STATUS_UNSUCCESSFUL;
         if (memcmp(Row->PermanentPhysicalAddress,
                    __PdoGetPermanentAddress(Pdo),
-                   sizeof (ETHERNET_ADDRESS)) == 0)
-            goto fail7;
+                   sizeof (ETHERNET_ADDRESS)) != 0)
+            continue;
+
+        status = STATUS_UNSUCCESSFUL;
+        goto fail7;
+    }
+
+    //
+    // If there is a stack bound then restore any settings that
+    // may have been saved from an aliasing emulated device.
+    //
+    status = PdoGetInterfaceGuid(Pdo, Key, &Guid);
+    if (NT_SUCCESS(status)) {
+        for (Index = 0; Index < Table->NumEntries; Index++) {
+            Row = &Table->Table[Index];
+
+            if (!IsEqualGUID(&Row->InterfaceGuid, &Guid))
+                continue;
+
+            (VOID) SettingsRestore(Key,
+                                   Row->Alias,
+                                   Row->Description,
+                                   &Row->InterfaceGuid,
+                                   &Row->InterfaceLuid);
+            break;
+        }
     }
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
@@ -1156,11 +1232,18 @@ fail8:
     Error("fail8\n");
 
     __FreeMibTable(Table);
+
     goto fail6;
 
 fail7:
     Error("fail7\n");
 
+    (VOID) SettingsSave(Key,
+                        Row->Alias,
+                        Row->Description,
+                        &Row->InterfaceGuid,
+                        &Row->InterfaceLuid);
+
     DriverRequestReboot();
     __FreeMibTable(Table);
 
diff --git a/src/xenvif/settings.c b/src/xenvif/settings.c
new file mode 100644
index 0000000..145e83d
--- /dev/null
+++ b/src/xenvif/settings.c
@@ -0,0 +1,495 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+
+#include "registry.h"
+#include "driver.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+#define SETTINGS_TAG 'TTES'
+
+static FORCEINLINE PVOID
+__SettingsAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocateNonPagedPoolWithTag(Length, SETTINGS_TAG);
+}
+
+static FORCEINLINE VOID
+__SettingsFree(
+    IN  PVOID   Buffer
+    )
+{
+    __FreePoolWithTag(Buffer, SETTINGS_TAG);
+}
+
+static NTSTATUS
+SettingsCopyValue(
+    IN  PVOID           Context,
+    IN  HANDLE          SourceKey,
+    IN  PANSI_STRING    Name,
+    IN  ULONG           Type
+    )
+{
+    HANDLE              DestinationKey = (HANDLE)Context;
+    NTSTATUS            status;
+
+    Trace("%Z\n", Name);
+
+    switch (Type) {
+    case REG_DWORD: {
+        ULONG   Value;
+
+        status = RegistryQueryDwordValue(SourceKey,
+                                         Name->Buffer,
+                                         &Value);
+        if (NT_SUCCESS(status))
+            (VOID) RegistryUpdateDwordValue(DestinationKey,
+                                            Name->Buffer,
+                                            Value);
+
+        break;
+    }
+    case REG_SZ:
+    case REG_MULTI_SZ: {
+        PANSI_STRING    Value;
+
+        status = RegistryQuerySzValue(SourceKey,
+                                      Name->Buffer,
+                                      &Value);
+        if (NT_SUCCESS(status)) {
+            (VOID) RegistryUpdateSzValue(DestinationKey,
+                                         Name->Buffer,
+                                         Value);
+            RegistryFreeSzValue(Value);
+        }
+
+        break;
+    }
+    case REG_BINARY: {
+        PVOID   Value;
+        ULONG   Length;
+
+        status = RegistryQueryBinaryValue(SourceKey,
+                                          Name->Buffer,
+                                          &Value,
+                                          &Length);
+        if (NT_SUCCESS(status)) {
+            (VOID) RegistryUpdateBinaryValue(DestinationKey,
+                                             Name->Buffer,
+                                             Value,
+                                             Length);
+            RegistryFreeBinaryValue(Value);
+        }
+
+        break;
+    }
+    default:
+        ASSERT(FALSE);
+    }
+
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+SettingsCopyInterface(
+    IN  HANDLE  SettingsKey,
+    IN  PCHAR   SaveKeyName,
+    IN  PCHAR   InterfacesPath,
+    IN  PCHAR   InterfacePrefix,
+    IN  PCHAR   InterfaceName,
+    IN  BOOLEAN Save
+    )
+{
+    ULONG       Length;
+    HANDLE      InterfacesKey;
+    PCHAR       KeyName;
+    HANDLE      Key;
+    HANDLE      SaveKey;
+    NTSTATUS    status;
+
+    Trace("====>\n");
+
+    status = RegistryOpenSubKey(NULL,
+                                InterfacesPath,
+                                KEY_ALL_ACCESS,
+                                &InterfacesKey);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    Length = (ULONG)((strlen(InterfacePrefix) +
+                      strlen(InterfaceName) +
+                      1) * sizeof (CHAR));
+
+    KeyName = __SettingsAllocate(Length);
+
+    status = STATUS_NO_MEMORY;
+    if (KeyName == NULL)
+        goto fail2;
+
+    status = RtlStringCbPrintfA(KeyName,
+                                Length,
+                                "%s%s",
+                                InterfacePrefix,
+                                InterfaceName);
+    ASSERT(NT_SUCCESS(status));
+
+    Trace("%s %s\\%s\n",
+          (Save) ? "FROM" : "TO",
+          InterfacesPath,
+          KeyName);
+
+    status = (!Save) ?
+        RegistryCreateSubKey(InterfacesKey,
+                             KeyName,
+                             REG_OPTION_NON_VOLATILE,
+                             &Key) :
+        RegistryOpenSubKey(InterfacesKey,
+                           KeyName,
+                           KEY_READ,
+                           &Key);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    status = (Save) ?
+        RegistryCreateSubKey(SettingsKey,
+                             SaveKeyName,
+                             REG_OPTION_NON_VOLATILE,
+                             &SaveKey) :
+        RegistryOpenSubKey(SettingsKey,
+                           SaveKeyName,
+                           KEY_READ,
+                           &SaveKey);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    status = (Save) ?
+        RegistryEnumerateValues(Key,
+                                SettingsCopyValue,
+                                (PVOID)SaveKey) :
+        // Restore
+        RegistryEnumerateValues(SaveKey,
+                                SettingsCopyValue,
+                                (PVOID)Key);
+    if (!NT_SUCCESS(status))
+        goto fail5;
+
+    RegistryCloseKey(SaveKey);
+
+    if (!Save)
+        (VOID) RegistryDeleteSubKey(SettingsKey, SaveKeyName);
+
+    RegistryCloseKey(Key);
+
+    __SettingsFree(KeyName);
+
+    RegistryCloseKey(InterfacesKey);
+
+    Trace("<====\n");
+
+    return STATUS_SUCCESS;
+
+fail5:
+    Error("fail5\n");
+
+    RegistryCloseKey(SaveKey);
+
+fail4:
+    Error("fail4\n");
+
+    RegistryCloseKey(Key);
+
+fail3:
+    Error("fail3\n");
+
+    __SettingsFree(KeyName);
+
+fail2:
+    Error("fail2\n");
+
+    RegistryCloseKey(InterfacesKey);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+#define IPV6_PATH 
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nsi\\{eb004a11-9b1a-11d4-9123-0050047759bc}\\10"
+
+static VOID
+SettingsCopyIpVersion6Addresses(
+    IN  HANDLE  SettingsKey,
+    IN  PCHAR   ValueName,
+    IN  BOOLEAN Save
+    )
+{
+    HANDLE      ValueKey;
+    PVOID       Value;
+    ULONG       Length;
+    NTSTATUS    status;
+
+    Trace("====>\n");
+
+    status = RegistryOpenSubKey(NULL,
+                                IPV6_PATH,
+                                (Save) ? KEY_READ : KEY_ALL_ACCESS,
+                                &ValueKey);
+    if (!NT_SUCCESS(status))
+        goto done;
+
+    Trace("%s %s\\%s\n",
+          (Save) ? "FROM" : "TO",
+          IPV6_PATH,
+          ValueName);
+
+    if (Save) {
+        status = RegistryQueryBinaryValue(ValueKey,
+                                          ValueName,
+                                          &Value,
+                                          &Length);
+        if (NT_SUCCESS(status))
+            (VOID) RegistryUpdateBinaryValue(SettingsKey,
+                                             "IpVersion6Addresses",
+                                             Value,
+                                             Length);
+    } else { // Restore
+        status = RegistryQueryBinaryValue(SettingsKey,
+                                          "IpVersion6Addresses",
+                                          &Value,
+                                          &Length);
+        if (NT_SUCCESS(status))
+            (VOID) RegistryUpdateBinaryValue(ValueKey,
+                                             ValueName,
+                                             Value,
+                                             Length);
+    }
+
+    RegistryCloseKey(ValueKey);
+
+done:
+    Trace("<====\n");
+}
+
+#define INTERFACES_PATH(_Name) 
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\" ## #_Name ## 
"\\Parameters\\Interfaces\\"
+
+static NTSTATUS
+SettingsCopy(
+     IN HANDLE      SettingsKey,
+     IN LPGUID      InterfaceGuid,
+     IN PNET_LUID   InterfaceLuid,
+     IN BOOLEAN     Save
+     )
+{
+    UNICODE_STRING  Unicode;
+    ULONG           Length;
+    PCHAR           GuidName;
+    PCHAR           LuidName;
+    NTSTATUS        status;
+
+    Trace("====>\n");
+
+    status = RtlStringFromGUID(InterfaceGuid, &Unicode);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    Length = (ULONG)(((Unicode.Length / sizeof (WCHAR)) +
+                      1) * sizeof (CHAR));
+
+    GuidName = __SettingsAllocate(Length);
+
+    status = STATUS_NO_MEMORY;
+    if (GuidName == NULL)
+        goto fail2;
+
+    status = RtlStringCbPrintfA(GuidName,
+                                Length,
+                                "%wZ",
+                                &Unicode);
+    ASSERT(NT_SUCCESS(status));
+
+    (VOID) SettingsCopyInterface(SettingsKey,
+                                 "NetBT",
+                                 INTERFACES_PATH(NetBT),
+                                 "Tcpip_",
+                                 GuidName,
+                                 Save);
+
+    (VOID) SettingsCopyInterface(SettingsKey,
+                                 "Tcpip",
+                                 INTERFACES_PATH(Tcpip),
+                                 "",
+                                 GuidName,
+                                 Save);
+
+    (VOID) SettingsCopyInterface(SettingsKey,
+                                 "Tcpip6",
+                                 INTERFACES_PATH(Tcpip6),
+                                 "",
+                                 GuidName,
+                                 Save);
+
+    Length = (ULONG)(((sizeof (NET_LUID) * 2) +
+                      1) * sizeof (CHAR));
+
+    LuidName = __SettingsAllocate(Length);
+
+    status = STATUS_NO_MEMORY;
+    if (LuidName == NULL)
+        goto fail3;
+
+    status = RtlStringCbPrintfA(LuidName,
+                                Length,
+                                "%016llX",
+                                InterfaceLuid->Value);
+    ASSERT(NT_SUCCESS(status));
+
+    SettingsCopyIpVersion6Addresses(SettingsKey,
+                                    LuidName,
+                                    Save);
+
+    __SettingsFree(LuidName);
+
+    __SettingsFree(GuidName);
+
+    RtlFreeUnicodeString(&Unicode);
+
+    Trace("<====\n");
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+    __SettingsFree(GuidName);
+
+fail2:
+    Error("fail2\n");
+
+    RtlFreeUnicodeString(&Unicode);
+
+fail1:
+    Error("fail1\n", status);
+
+    return status;
+}
+
+NTSTATUS
+SettingsSave(
+     IN HANDLE      SoftwareKey,
+     IN PWCHAR      Alias,
+     IN PWCHAR      Description,
+     IN LPGUID      InterfaceGuid,
+     IN PNET_LUID   InterfaceLuid
+     )
+{
+    HANDLE          SettingsKey;
+    NTSTATUS        status;
+
+    Info("FROM %ws (%ws)\n", Alias, Description);
+
+    status = RegistryCreateSubKey(SoftwareKey,
+                                  "Settings",
+                                  REG_OPTION_NON_VOLATILE,
+                                  &SettingsKey);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = SettingsCopy(SettingsKey, InterfaceGuid, InterfaceLuid, TRUE);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    RegistryCloseKey(SettingsKey);
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+    RegistryCloseKey(SettingsKey);
+
+fail1:
+    Error("fail1\n", status);
+
+    return status;
+}
+
+NTSTATUS
+SettingsRestore(
+     IN HANDLE      SoftwareKey,
+     IN PWCHAR      Alias,
+     IN PWCHAR      Description,
+     IN LPGUID      InterfaceGuid,
+     IN PNET_LUID   InterfaceLuid
+     )
+{
+    HANDLE          SettingsKey;
+    NTSTATUS        status;
+
+    status = RegistryOpenSubKey(SoftwareKey,
+                                "Settings",
+                                KEY_ALL_ACCESS,
+                                &SettingsKey);
+    if (!NT_SUCCESS(status)) {
+        if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+            goto done;
+
+        goto fail1;
+    }
+
+    Info("TO %ws (%ws)\n", Alias, Description);
+
+    status = SettingsCopy(SettingsKey, InterfaceGuid, InterfaceLuid, FALSE);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    RegistryCloseKey(SettingsKey);
+
+    (VOID) RegistryDeleteSubKey(SoftwareKey, "Settings");
+
+done:
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+    RegistryCloseKey(SettingsKey);
+
+fail1:
+    Error("fail1\n", status);
+
+    return status;
+}
diff --git a/src/xenvif/settings.h b/src/xenvif/settings.h
new file mode 100644
index 0000000..7bd1824
--- /dev/null
+++ b/src/xenvif/settings.h
@@ -0,0 +1,53 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENVIF_SETTINGS_H
+#define _XENVIF_SETTINGS_H
+
+extern NTSTATUS
+SettingsSave(
+     IN HANDLE      SoftwareKey,
+     IN PWCHAR      Alias,
+     IN PWCHAR      Description,
+     IN LPGUID      InterfaceGuid,
+     IN PNET_LUID   InterfaceLuid
+     );
+
+extern NTSTATUS
+SettingsRestore(
+     IN HANDLE      SoftwareKey,
+     IN PWCHAR      Alias,
+     IN PWCHAR      Description,
+     IN LPGUID      InterfaceGuid,
+     IN PNET_LUID   InterfaceLuid
+     );
+
+#endif  // _XENVIF_SETTINGS_H
diff --git a/vs2012/xenvif/xenvif.vcxproj b/vs2012/xenvif/xenvif.vcxproj
index c2c37d1..13be8a2 100644
--- a/vs2012/xenvif/xenvif.vcxproj
+++ b/vs2012/xenvif/xenvif.vcxproj
@@ -87,6 +87,7 @@
     <ClCompile Include="../../src/xenvif/pdo.c" />
     <ClCompile Include="../../src/xenvif/receiver.c" />
     <ClCompile Include="../../src/xenvif/registry.c" />
+    <ClCompile Include="../../src/xenvif/settings.c" />
     <ClCompile Include="../../src/xenvif/thread.c" />
     <ClCompile Include="../../src/xenvif/transmitter.c" />
     <ClCompile Include="../../src/xenvif/vif.c" />
diff --git a/vs2013/xenvif/xenvif.vcxproj b/vs2013/xenvif/xenvif.vcxproj
index 879fe1d..19ac1ed 100644
--- a/vs2013/xenvif/xenvif.vcxproj
+++ b/vs2013/xenvif/xenvif.vcxproj
@@ -90,6 +90,7 @@
     <ClCompile Include="../../src/xenvif/pdo.c" />
     <ClCompile Include="../../src/xenvif/receiver.c" />
     <ClCompile Include="../../src/xenvif/registry.c" />
+    <ClCompile Include="../../src/xenvif/settings.c" />
     <ClCompile Include="../../src/xenvif/thread.c" />
     <ClCompile Include="../../src/xenvif/transmitter.c" />
     <ClCompile Include="../../src/xenvif/vif.c" />
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.