Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestService.cpp
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestService.cpp	(revision 60416)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestService.cpp	(revision 60417)
@@ -55,6 +55,7 @@
 #include <iprt/thread.h>
 
+#include "UsbTestServiceCfg.h"
 #include "UsbTestServiceInternal.h"
-#include "UsbTestServiceCfg.h"
+#include "UsbTestServiceGadget.h"
 
 
@@ -63,4 +64,7 @@
 *   Structures and Typedefs                                                                                                      *
 *********************************************************************************************************************************/
+
+#define UTS_USBIP_PORT_FIRST 3240
+#define UTS_USBIP_PORT_LAST  3340
 
 /**
@@ -94,4 +98,8 @@
     /** Client hostname. */
     char                  *pszHostname;
+    /** Gadget host handle. */
+    UTSGADGETHOST          hGadgetHost;
+    /** Handle fo the current configured gadget. */
+    UTSGADGET              hGadget;
 } UTSCLIENT;
 /** Pointer to a UTS client instance. */
@@ -115,5 +123,5 @@
 /** The select transport layer. */
 static PCUTSTRANSPORT       g_pTransport;
-/** The scratch path. */
+/** The config path. */
 static char                 g_szCfgPath[RTPATH_MAX];
 /** The scratch path. */
@@ -154,4 +162,10 @@
 /** List of new clients waiting to be picked up by the client worker thread. */
 static RTLISTANCHOR         g_LstClientsNew;
+/** First USB/IP port we can use. */
+static uint16_t             g_uUsbIpPortFirst = UTS_USBIP_PORT_FIRST;
+/** Last USB/IP port we can use. */
+static uint16_t             g_uUsbIpPortLast  = UTS_USBIP_PORT_LAST;
+/** Next free port. */
+static uint16_t             g_uUsbIpPortNext  = UTS_USBIP_PORT_FIRST;
 
 
@@ -527,4 +541,16 @@
 
 /**
+ * Creates the configuration from the given GADGET CREATE packet.
+ *
+ * @returns IPRT status code.
+ * @param   pReq                The gadget create request.
+ * @param   paCfg               The array of configuration items.
+ */
+static int utsDoGadgetCreateFillCfg(PUTSPKTREQGDGTCTOR pReq, PUTSGADGETCFGITEM paCfg)
+{
+    return VERR_NOT_IMPLEMENTED;
+}
+
+/**
  * Verifies and acknowledges a "BYE" request.
  *
@@ -553,4 +579,6 @@
 static int utsDoHowdy(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
 {
+    int rc = VINF_SUCCESS;
+
     if (pPktHdr->cb != sizeof(UTSPKTREQHOWDY))
         return utsReplyBadSize(pClient, pPktHdr, sizeof(UTSPKTREQHOWDY));
@@ -576,10 +604,201 @@
         return utsReplyRC(pClient, pPktHdr, VERR_NO_MEMORY, "Failed to alllocate memory for the hostname string");
 
-    int rc = utsReplyAck(pClient, pPktHdr);
+    if (pReq->fUsbConn & UTSPKT_HOWDY_CONN_F_PHYSICAL)
+        return utsReplyRC(pClient, pPktHdr, VERR_NOT_SUPPORTED, "Physical connections are not yet supported");
+
+    if (pReq->fUsbConn & UTSPKT_HOWDY_CONN_F_USBIP)
+    {
+        /* Set up the USB/IP server, find an unused port we can start the server on. */
+        UTSGADGETCFGITEM aCfg[2];
+
+        uint16_t uPort = g_uUsbIpPortNext;
+
+        if (g_uUsbIpPortNext == g_uUsbIpPortLast)
+            g_uUsbIpPortNext = g_uUsbIpPortFirst;
+        else
+            g_uUsbIpPortNext++;
+
+        aCfg[0].pszKey      = "UsbIp/Port";
+        aCfg[0].Val.enmType = UTSGADGETCFGTYPE_UINT16;
+        aCfg[0].Val.u.u16   = uPort;
+        aCfg[1].pszKey      = NULL;
+
+        rc = utsGadgetHostCreate(UTSGADGETHOSTTYPE_USBIP, &aCfg[0], &pClient->hGadgetHost);
+        if (RT_SUCCESS(rc))
+        {
+            /* Send the reply with the configured USB/IP port. */
+            UTSPKTREPHOWDY Rep;
+
+            RT_ZERO(Rep);
+
+            Rep.uVersion         = UTS_PROTOCOL_VS;
+            Rep.fUsbConn         = UTSPKT_HOWDY_CONN_F_USBIP;
+            Rep.uUsbIpPort       = uPort;
+            Rep.cUsbIpDevices    = 1;
+            Rep.cPhysicalDevices = 0;
+
+            rc = utsReplyInternal(pClient, &Rep.Sts, "ACK     ", sizeof(Rep) - sizeof(UTSPKTSTS));
+            if (RT_SUCCESS(rc))
+            {
+                g_pTransport->pfnNotifyHowdy(pClient->pTransportClient);
+                pClient->enmState = UTSCLIENTSTATE_READY;
+                RTDirRemoveRecursive(g_szScratchPath, RTDIRRMREC_F_CONTENT_ONLY);
+            }
+        }
+        else
+            return utsReplyRC(pClient, pPktHdr, rc, "Creating the USB/IP gadget host failed");
+    }
+    else
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_PARAMETER, "No access method requested");
+
+    return rc;
+}
+
+/**
+ * Verifies and processes a "GADGET CREATE" request.
+ *
+ * @returns IPRT status code.
+ * @param   pClient             The UTS client structure.
+ * @param   pPktHdr             The gadget create packet.
+ */
+static int utsDoGadgetCreate(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
+{
+    int rc = VINF_SUCCESS;
+
+    if (pPktHdr->cb < sizeof(UTSPKTREQGDGTCTOR))
+        return utsReplyBadSize(pClient, pPktHdr, sizeof(UTSPKTREQGDGTCTOR));
+
+    if (   pClient->enmState != UTSCLIENTSTATE_READY
+        || pClient->hGadgetHost == NIL_UTSGADGETHOST)
+        return utsReplyInvalidState(pClient, pPktHdr);
+
+    PUTSPKTREQGDGTCTOR pReq = (PUTSPKTREQGDGTCTOR)pPktHdr;
+
+    if (pReq->u32GdgtType != UTSPKT_GDGT_CREATE_TYPE_TEST)
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_PARAMETER, "The given gadget type is not supported");
+
+    if (pReq->u32GdgtAccess != UTSPKT_GDGT_CREATE_ACCESS_USBIP)
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_PARAMETER, "The given gadget access method is not supported");
+
+    PUTSGADGETCFGITEM paCfg = NULL;
+    if (pReq->u32CfgItems > 0)
+    {
+        paCfg = (PUTSGADGETCFGITEM)RTMemAllocZ((pReq->u32CfgItems + 1) * sizeof(UTSGADGETCFGITEM));
+        if (RT_UNLIKELY(!paCfg))
+            return utsReplyRC(pClient, pPktHdr, VERR_NO_MEMORY, "Failed to allocate memory for configration items");
+
+        rc = utsDoGadgetCreateFillCfg(pReq, paCfg);
+        if (RT_FAILURE(rc))
+        {
+            RTMemFree(paCfg);
+            return utsReplyRC(pClient, pPktHdr, rc, "Failed to parse configuration");
+        }
+    }
+
+    rc = utsGadgetCreate(pClient->hGadgetHost, UTSGADGETCLASS_TEST, paCfg, &pClient->hGadget);
     if (RT_SUCCESS(rc))
     {
-        g_pTransport->pfnNotifyHowdy(pClient->pTransportClient);
-        RTDirRemoveRecursive(g_szScratchPath, RTDIRRMREC_F_CONTENT_ONLY);
+        UTSPKTREPGDGTCTOR Rep;
+        RT_ZERO(Rep);
+
+        Rep.idGadget = 0;
+        rc = utsReplyInternal(pClient, &Rep.Sts, "ACK     ", sizeof(Rep) - sizeof(UTSPKTSTS));
     }
+    else
+        rc = utsReplyRC(pClient, pPktHdr, rc, "Failed to create gadget with %Rrc\n", rc);
+
+    return rc;
+}
+
+/**
+ * Verifies and processes a "GADGET DESTROY" request.
+ *
+ * @returns IPRT status code.
+ * @param   pClient             The UTS client structure.
+ * @param   pPktHdr             The gadget destroy packet.
+ */
+static int utsDoGadgetDestroy(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
+{
+    if (pPktHdr->cb != sizeof(UTSPKTREQGDGTDTOR))
+        return utsReplyBadSize(pClient, pPktHdr, sizeof(UTSPKTREQGDGTDTOR));
+
+    if (   pClient->enmState != UTSCLIENTSTATE_READY
+        || pClient->hGadgetHost == NIL_UTSGADGETHOST)
+        return utsReplyInvalidState(pClient, pPktHdr);
+
+    PUTSPKTREQGDGTDTOR pReq = (PUTSPKTREQGDGTDTOR)pPktHdr;
+
+    if (pReq->idGadget != 0)
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_HANDLE, "The given gadget handle is invalid");
+    if (pClient->hGadget == NIL_UTSGADGET)
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_STATE, "The gadget is not set up");
+
+    utsGadgetRelease(pClient->hGadget);
+    pClient->hGadget = NIL_UTSGADGET;
+
+    return utsReplyAck(pClient, pPktHdr);
+}
+
+/**
+ * Verifies and processes a "GADGET CONNECT" request.
+ *
+ * @returns IPRT status code.
+ * @param   pClient             The UTS client structure.
+ * @param   pPktHdr             The gadget connect packet.
+ */
+static int utsDoGadgetConnect(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
+{
+    if (pPktHdr->cb != sizeof(UTSPKTREQGDGTCNCT))
+        return utsReplyBadSize(pClient, pPktHdr, sizeof(UTSPKTREQGDGTCNCT));
+
+    if (   pClient->enmState != UTSCLIENTSTATE_READY
+        || pClient->hGadgetHost == NIL_UTSGADGETHOST)
+        return utsReplyInvalidState(pClient, pPktHdr);
+
+    PUTSPKTREQGDGTCNCT pReq = (PUTSPKTREQGDGTCNCT)pPktHdr;
+
+    if (pReq->idGadget != 0)
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_HANDLE, "The given gadget handle is invalid");
+    if (pClient->hGadget == NIL_UTSGADGET)
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_STATE, "The gadget is not set up");
+
+    int rc = utsGadgetConnect(pClient->hGadget);
+    if (RT_SUCCESS(rc))
+        rc = utsReplyAck(pClient, pPktHdr);
+    else
+        rc = utsReplyRC(pClient, pPktHdr, rc, "Failed to connect the gadget");
+
+    return rc;
+}
+
+/**
+ * Verifies and processes a "GADGET DISCONNECT" request.
+ *
+ * @returns IPRT status code.
+ * @param   pClient             The UTS client structure.
+ * @param   pPktHdr             The gadget disconnect packet.
+ */
+static int utsDoGadgetDisconnect(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
+{
+    if (pPktHdr->cb != sizeof(UTSPKTREQGDGTDCNT))
+        return utsReplyBadSize(pClient, pPktHdr, sizeof(UTSPKTREQGDGTDCNT));
+
+    if (   pClient->enmState != UTSCLIENTSTATE_READY
+        || pClient->hGadgetHost == NIL_UTSGADGETHOST)
+        return utsReplyInvalidState(pClient, pPktHdr);
+
+    PUTSPKTREQGDGTDCNT pReq = (PUTSPKTREQGDGTDCNT)pPktHdr;
+
+    if (pReq->idGadget != 0)
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_HANDLE, "The given gadget handle is invalid");
+    if (pClient->hGadget == NIL_UTSGADGET)
+        return utsReplyRC(pClient, pPktHdr, VERR_INVALID_STATE, "The gadget is not set up");
+
+    int rc = utsGadgetDisconnect(pClient->hGadget);
+    if (RT_SUCCESS(rc))
+        rc = utsReplyAck(pClient, pPktHdr);
+    else
+        rc = utsReplyRC(pClient, pPktHdr, rc, "Failed to disconnect the gadget");
+
     return rc;
 }
@@ -609,4 +828,13 @@
     else if (utsIsSameOpcode(pPktHdr, UTSPKT_OPCODE_BYE))
         rc = utsDoBye(pClient, pPktHdr);
+    /* Gadget API. */
+    else if (utsIsSameOpcode(pPktHdr, UTSPKT_OPCODE_GADGET_CREATE))
+        rc = utsDoGadgetCreate(pClient, pPktHdr);
+    else if (utsIsSameOpcode(pPktHdr, UTSPKT_OPCODE_GADGET_DESTROY))
+        rc = utsDoGadgetCreate(pClient, pPktHdr);
+    else if (utsIsSameOpcode(pPktHdr, UTSPKT_OPCODE_GADGET_CONNECT))
+        rc = utsDoGadgetConnect(pClient, pPktHdr);
+    else if (utsIsSameOpcode(pPktHdr, UTSPKT_OPCODE_GADGET_DISCONNECT))
+        rc = utsDoGadgetDisconnect(pClient, pPktHdr);
     /* Misc: */
     else
@@ -628,4 +856,8 @@
     if (pClient->pszHostname)
         RTStrFree(pClient->pszHostname);
+    if (pClient->hGadget != NIL_UTSGADGET)
+        utsGadgetRelease(pClient->hGadget);
+    if (pClient->hGadgetHost != NIL_UTSGADGETHOST)
+        utsGadgetHostRelease(pClient->hGadgetHost);
     RTMemFree(pClient);
 }
@@ -768,4 +1000,7 @@
             pClient->enmState         = UTSCLIENTSTATE_INITIALISING;
             pClient->pTransportClient = pTransportClient;
+            pClient->pszHostname      = NULL;
+            pClient->hGadgetHost      = NIL_UTSGADGETHOST;
+            pClient->hGadget          = NIL_UTSGADGET;
         }
         else
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.cpp
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.cpp	(revision 60416)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.cpp	(revision 60417)
@@ -144,2 +144,20 @@
 }
 
+
+DECLHIDDEN(int) utsGadgetConnect(UTSGADGET hGadget)
+{
+    PUTSGADGETINT pThis = hGadget;
+
+    AssertPtrReturn(pThis, 0);
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+DECLHIDDEN(int) utsGadgetDisconnect(UTSGADGET hGadget)
+{
+    PUTSGADGETINT pThis = hGadget;
+
+    AssertPtrReturn(pThis, 0);
+    return VERR_NOT_IMPLEMENTED;
+}
+
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.h
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.h	(revision 60416)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.h	(revision 60417)
@@ -76,4 +76,5 @@
     /** Signed 64bit integer. */
     UTSGADGETCFGTYPE_INT64,
+    /** 32bit hack. */
     UTSGADGETCFGTYPE_32BIT_HACK = 0x7fffffff
 } UTSGADGETCFGTYPE;
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceProtocol.h
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceProtocol.h	(revision 60416)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceProtocol.h	(revision 60417)
@@ -146,4 +146,87 @@
 
 #define UTSPKT_OPCODE_GADGET_CREATE     "GDGTCRT "
+
+/**
+ * The GADGET CREATE request structure.
+ */
+typedef struct UTSPKTREQGDGTCTOR
+{
+    /** Embedded packet header. */
+    UTSPKTHDR       Hdr;
+    /** Gadget type. */
+    uint32_t        u32GdgtType;
+    /** Access methods. */
+    uint32_t        u32GdgtAccess;
+    /** Number of config items - following this structure. */
+    uint32_t        u32CfgItems;
+    /** Reserved. */
+    uint32_t        u32Rsvd0;
+} UTSPKTREQGDGTCTOR;
+AssertCompileSizeAlignment(UTSPKTREQGDGTCTOR, UTSPKT_ALIGNMENT);
+/** Pointer to a GADGET CREATE structure. */
+typedef UTSPKTREQGDGTCTOR *PUTSPKTREQGDGTCTOR;
+
+/** Gadget type - Test device. */
+#define UTSPKT_GDGT_CREATE_TYPE_TEST UINT32_C(0x1)
+
+/** Gadget acess method - USB/IP. */
+#define UTSPKT_GDGT_CREATE_ACCESS_USBIP UINT32_C(0x1)
+
+/**
+ * Configuration item.
+ */
+typedef struct UTSPKTREQGDGTCTORCFGITEM
+{
+    /** Size of the key incuding termination in bytes. */
+    uint32_t        u32KeySize;
+    /** Item type. */
+    uint32_t        u32Type;
+    /** Size of the value string including termination in bytes. */
+    uint32_t        u32ValSize;
+    /** Reserved. */
+    uint32_t        u32Rsvd0;
+} UTSPKTREQGDGTCTORCFGITEM;
+AssertCompileSizeAlignment(UTSPKTREQGDGTCTORCFGITEM, UTSPKT_ALIGNMENT);
+/** Pointer to a configuration item. */
+typedef UTSPKTREQGDGTCTORCFGITEM *PUTSPKTREQGDGTCTORCFGITEM;
+
+/** Boolean configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_BOOLEAN UINT32_C(1)
+/** String configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_STRING  UINT32_C(2)
+/** Unsigned 8-bit integer configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_UINT8   UINT32_C(3)
+/** Unsigned 16-bit integer configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_UINT16  UINT32_C(4)
+/** Unsigned 32-bit integer configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_UINT32  UINT32_C(5)
+/** Unsigned 64-bit integer configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_UINT64  UINT32_C(6)
+/** Signed 8-bit integer configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_INT8    UINT32_C(7)
+/** Signed 16-bit integer configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_INT16   UINT32_C(8)
+/** Signed 32-bit integer configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_INT32   UINT32_C(9)
+/** Signed 64-bit integer configuration item type. */
+#define UTSPKT_GDGT_CFG_ITEM_TYPE_INT64   UINT32_C(10)
+
+/**
+ * The GADGET CREATE reply structure.
+ */
+typedef struct UTSPKTREPGDGTCTOR
+{
+    /** Status packet. */
+    UTSPKTSTS       Sts;
+    /** The gadget ID on success. */
+    uint32_t        idGadget;
+    /** Padding - reserved. */
+    uint8_t         au8Padding[12];
+} UTSPKTREPGDGTCTOR;
+AssertCompileSizeAlignment(UTSPKTREPGDGTCTOR, UTSPKT_ALIGNMENT);
+/** Pointer to a GADGET CREATE structure. */
+typedef UTSPKTREPGDGTCTOR *PUTSPKTREPGDGTCTOR;
+
+
 #define UTSPKT_OPCODE_GADGET_DESTROY    "GDGTDTOR"
 
