On Fri, Apr 24, 2009 at 4:07 AM, Antonio Augusto (Mancha)
<[email protected]> wrote:
> Hey Guys,
>
> I'm working on a security project and would like to do some
> experiments with arp/dns poisoning, but to do so I'd need that the
> network the VMs are connected behaved like a switched one, that is:
> packets arrive only on the interface to where they are destined.
> I've tried looking on the code, specially in
> src/VBox/Devices/Network/DrvIntNet.cpp but I couldn't quite understand
> how the "receiving" works ...
> I see that there is a ringbuffer one the drvIntNetAsyncIoRun , but i
> don't get if this buffer is exclusive for each interface or if its the
> "network" buffer.
>
> Its a bit late in my side of the world, and my eyes are heavy, so I
> might be misunderstanding something, but if one of the developers
> could point me on the right direction, and maybe elaborate a bit on
> how network work on VBox It'd be of great help.
>
> Thanks a lot!

Hola!

Precisely I'm working in a patch to make virtualbox host-only and
internal networks work in "mesh" mode. So that I can configure each
interface connected to a network to which other network interfaces is
it directly connected to. I want to do that for testing using
virtuabox my final project which is an implementation of the AODV mesh
networks routing protocol. Yesterday I "finished" the patch i.e. it
compiles and in theory it should work but I didn't have enough time
yet to test it. I attach it to this email so that others can review
the patch and/or help me developing it. My final aim is that it works
and it gets integrated in trunk :P. Any comments about this patch are
welcome!

Regards,
      Eduardo Robles Elvira.
Index: include/VBox/intnet.h
===================================================================
--- include/VBox/intnet.h	(revisión: 18845)
+++ include/VBox/intnet.h	(copia de trabajo)
@@ -35,6 +35,7 @@
 #include <VBox/sup.h>
 #include <iprt/assert.h>
 #include <iprt/asm.h>
+#include <iprt/types.h>
 
 __BEGIN_DECLS
 
@@ -664,12 +665,14 @@
 #define INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST             RT_BIT_32(6)
 /** Ignore any requests for promiscuous mode on the trunk host connection, quietly applied/ignored on open. */
 #define INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST     RT_BIT_32(7)
+/** Mesh mode. */
+#define INTNET_OPEN_FLAGS_MESH_MODE                             RT_BIT_32(8)
 /** The mask of flags which causes flag incompatibilities. */
 #define INTNET_OPEN_FLAGS_COMPATIBILITY_XOR_MASK                (RT_BIT_32(0) | RT_BIT_32(1) | RT_BIT_32(2) | RT_BIT_32(4) | RT_BIT_32(6))
 /** The mask of flags is always ORed in, even on open. (the quiet stuff) */
 #define INTNET_OPEN_FLAGS_SECURITY_OR_MASK                      (RT_BIT_32(3) | RT_BIT_32(5) | RT_BIT_32(7))
 /** The mask of valid flags. */
-#define INTNET_OPEN_FLAGS_MASK                                  UINT32_C(0x000000ff)
+#define INTNET_OPEN_FLAGS_MASK                                  UINT32_C(0x0000008f)
 /** @} */
 
 /** The maximum length of a network name. */
@@ -678,7 +681,6 @@
 /** The maximum length of a trunk name. */
 #define INTNET_MAX_TRUNK_NAME       64
 
-
 /**
  * Request buffer for INTNETR0OpenReq / VMMR0_DO_INTNET_OPEN.
  * @see INTNETR0Open.
@@ -695,6 +697,10 @@
     /** What to connect to the trunk port. (input)
      * This is specific to the trunk type below. */
     char            szTrunk[INTNET_MAX_TRUNK_NAME];
+    /** The uuid of the machine in which the network interface resides */
+    char            machineId[RTUUID_STR_LENGTH];
+    /** The port in which this interface is connected in the above machine. */
+    uint32_t        machinePort;
     /** The type of trunk link (NAT, Filter, TAP, etc). (input) */
     INTNETTRUNKTYPE enmTrunkType;
     /** Flags, see INTNET_OPEN_FLAGS_*. (input) */
@@ -703,6 +709,8 @@
     uint32_t        cbSend;
     /** The size of the receive buffer. (input) */
     uint32_t        cbRecv;
+    /** The slot to which the network interface is connected to */
+    uint32_t        slot;
     /** The handle to the network interface. (output) */
     INTNETIFHANDLE  hIf;
 } INTNETOPENREQ;
@@ -797,7 +805,30 @@
 
 INTNETR0DECL(int) INTNETR0IfSetMacAddressReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETMACADDRESSREQ pReq);
 
+/**
+ * Request buffer for INTNETR0IfAddMeshNode / VMMR0_DO_INTNET_IF_ADD_MESH_NODE
+ * @see INTNETR0IfSetMacAddress.
+ */
+typedef struct INTNETIFADDMESHNODEREQ
+{
+    /** The request header. */
+    SUPVMMR0REQHDR  Hdr;
+    /** Alternative to passing the taking the session from the VM handle.
+     * Either use this member or use the VM handle, don't do both. */
+    PSUPDRVSESSION  pSession;
+    /** Handle to the interface. */
+    INTNETIFHANDLE  hIf;
+    /** The slot to which the network interface is associated with. */
+    uint32_t        slot;
+    /** The uuid of the machine in which the network interface resides */
+    char            machineId[RTUUID_STR_LENGTH];
+} INTNETIFADDMESHNODEREQ;
+/** Pointer to an INTNETIFADDMESHNODEREQ request buffer. */
+typedef INTNETIFADDMESHNODEREQ *PINTNETIFADDMESHNODEREQ;
 
+INTNETR0DECL(int) INTNETR0IfAddMeshNodeReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFADDMESHNODEREQ pReq);
+
+
 /**
  * Request buffer for INTNETR0IfSetActiveReq / VMMR0_DO_INTNET_IF_SET_ACTIVE.
  * @see INTNETR0IfSetActive.
@@ -896,10 +927,13 @@
  * @param   cbSend          The send buffer size.
  * @param   cbRecv          The receive buffer size.
  * @param   phIf            Where to store the handle to the network interface.
+ * @param   machineId       The id of machine the machine to which this interface is connected to.
+ * @param   slot            The slot to which this interface is associated with in the parent machine.
  */
 INTNETR0DECL(int) INTNETR0Open(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork,
                                INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags,
-                               unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf);
+                               unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf, const char *machineId,
+                               unsigned slot);
 
 /**
  * Close an interface.
@@ -944,6 +978,7 @@
  */
 INTNETR0DECL(int) INTNETR0IfSetPromiscuousMode( PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fPromiscuous);
 INTNETR0DECL(int) INTNETR0IfSetMacAddress(      PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PCRTMAC pMac);
+INTNETR0DECL(int) INTNETR0IfAddMeshNode(        PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, const char* machineId, uint32_t slot);
 INTNETR0DECL(int) INTNETR0IfSetActive(          PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fActive);
 
 /**
Index: include/VBox/vmm.h
===================================================================
--- include/VBox/vmm.h	(revisión: 18845)
+++ include/VBox/vmm.h	(copia de trabajo)
@@ -251,6 +251,8 @@
     VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,
     /** Call INTNETR0IfSetMacAddress(). */
     VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS,
+    /** Call INTNETR0IfAddMeshNode(). */
+    VMMR0_DO_INTNET_IF_ADD_MESH_NODE,
     /** Call INTNETR0IfSetActive(). */
     VMMR0_DO_INTNET_IF_SET_ACTIVE,
     /** Call INTNETR0IfSend(). */
Index: src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- src/VBox/VMM/VMMR0/VMMR0.cpp	(revisión: 18845)
+++ src/VBox/VMM/VMMR0/VMMR0.cpp	(copia de trabajo)
@@ -931,6 +931,13 @@
                 return VERR_NOT_SUPPORTED;
             return INTNETR0IfSetMacAddressReq(g_pIntNet, pSession, (PINTNETIFSETMACADDRESSREQ)pReqHdr);
 
+        case VMMR0_DO_INTNET_IF_ADD_MESH_NODE:
+            if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFADDMESHNODEREQ)pReqHdr)->pSession, pSession))
+                return VERR_INVALID_PARAMETER;
+            if (!g_pIntNet)
+                return VERR_NOT_SUPPORTED;
+            return INTNETR0IfAddMeshNodeReq(g_pIntNet, pSession, (PINTNETIFADDMESHNODEREQ)pReqHdr);
+            
         case VMMR0_DO_INTNET_IF_SET_ACTIVE:
             if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETACTIVEREQ)pReqHdr)->pSession, pSession))
                 return VERR_INVALID_PARAMETER;
Index: src/VBox/Devices/Network/SrvIntNetR0.cpp
===================================================================
--- src/VBox/Devices/Network/SrvIntNetR0.cpp	(revisión: 18845)
+++ src/VBox/Devices/Network/SrvIntNetR0.cpp	(copia de trabajo)
@@ -107,6 +107,7 @@
 /** Pointer to a const address cache. */
 typedef INTNETADDRCACHE const *PCINTNETADDRCACHE;
 
+struct INTNETMESHNODE;
 
 /**
  * A network interface.
@@ -159,10 +160,35 @@
     void                   *pvObj;
     /** The network layer address cache. (Indexed by type, 0 entry isn't used.) */
     INTNETADDRCACHE         aAddrCache[kIntNetAddrType_End];
+    /** The slot to which the network interface is associated with. */
+    uint32_t                slot;
+    /** The uuid of the machine in which the network interface resides */
+    char                    machineId[RTUUID_STR_LENGTH];
+    /** The list of mesh neighbours to which this interface is connected to */
+    struct INTNETMESHNODE  *meshNeighbours;
 } INTNETIF;
 /** Pointer to an internal network interface. */
 typedef INTNETIF *PINTNETIF;
 
+/**
+ * A reference  to a mesh node (which ultimately is a pointer to a network
+ * interface).
+ *
+ * Unless explicitly stated, all members are protect by the network semaphore.
+ */
+typedef struct INTNETMESHNODE
+{
+    /** The slot to which the network interface of the node is associated with. */
+    uint32_t                slot;
+    /** The uuid of the machine in which the network interface of the node resides */
+    char                    machineId[RTUUID_STR_LENGTH];
+    /** The network interface of the node */
+    PINTNETIF               pIf;
+    /** Pointer to the next mesh node.
+     * This is protected by the INTNET::FastMutex. */
+    struct INTNETMESHNODE  *pNext;
+} INTNETMESHNODE;
+typedef INTNETMESHNODE *PINTNETMESHNODE;
 
 /**
  * A trunk interface.
@@ -2089,9 +2115,14 @@
      *
      * Write the packet to all the interfaces and signal them.
      */
-    for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
-        if (pIf != pIfSender)
-            intnetR0IfSend(pIf, pIfSender, pSG, NULL);
+    if(!pIfSender || !(pIfSender->pNetwork->fFlags & INTNET_OPEN_FLAGS_MESH_MODE))
+        for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
+            if (pIf != pIfSender)
+                intnetR0IfSend(pIf, pIfSender, pSG, NULL);
+    else
+        for (PINTNETMESHNODE neighbour = pIfSender->meshNeighbours; neighbour; neighbour = neighbour->pNext)
+            if (neighbour->pIf)
+                intnetR0IfSend(neighbour->pIf, pIfSender, pSG, NULL);
 
     /*
      * Unless the trunk is the origin, broadcast it to both the wire
@@ -2279,20 +2310,36 @@
      * Only send to the interfaces with matching a MAC address.
      */
     bool fExactIntNetRecipient = false;
-    for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
-    {
-        bool fIt = false;
-        if (    (   !pIf->fMacSet
-                 || (fIt = !memcmp(&pIf->Mac, &pEthHdr->DstMac, sizeof(pIf->Mac))) )
-            ||  (   pIf->fPromiscuous
-                 && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))
-                 && pIf != pIfSender /* promiscuous mode: omit the sender */))
+    if(!pIfSender || !(pIfSender->pNetwork->fFlags & INTNET_OPEN_FLAGS_MESH_MODE))
+        for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
         {
-            Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac));
-            fExactIntNetRecipient |= fIt;
-            intnetR0IfSend(pIf, pIfSender, pSG, NULL);
+            bool fIt = false;
+            if (    (   !pIf->fMacSet
+                    || (fIt = !memcmp(&pIf->Mac, &pEthHdr->DstMac, sizeof(pIf->Mac))) )
+                ||  (   pIf->fPromiscuous
+                    && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))
+                    && pIf != pIfSender /* promiscuous mode: omit the sender */))
+            {
+                Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac));
+                fExactIntNetRecipient |= fIt;
+                intnetR0IfSend(pIf, pIfSender, pSG, NULL);
+            }
         }
-    }
+    else
+        for (PINTNETMESHNODE neighbour = pIfSender->meshNeighbours; neighbour; neighbour = neighbour->pNext)
+            if (neighbour->pIf)
+            {
+                bool fIt = false;
+                if (    (   !neighbour->pIf->fMacSet
+                        || (fIt = !memcmp(&neighbour->pIf->Mac, &pEthHdr->DstMac, sizeof(neighbour->pIf->Mac))) )
+                    ||  (   neighbour->pIf->fPromiscuous
+                        && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))))
+                {
+                    Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &neighbour->pIf->Mac));
+                    fExactIntNetRecipient |= fIt;
+                    intnetR0IfSend(neighbour->pIf, pIfSender, pSG, NULL);
+                }
+            }
 
     /*
      * Send it to the trunk?
@@ -2829,6 +2876,76 @@
 
 
 /**
+ * Add a new mesh node to the interface, but only if it's in mesh mode.
+ *
+ * @returns VBox status code.
+ * @param   pIntNet         The instance handle.
+ * @param   hIf             The interface handle.
+ * @param   pSession        The caller's session.
+ * @param   machineId       The id of machine the machine to which this interface is connected to.
+ * @param   slot            The slot to which this interface is associated with in the parent machine.
+ */
+INTNETR0DECL(int) INTNETR0IfAddMeshNode(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, const char *machineId, uint32_t slot)
+{
+    LogFlow(("INTNETR0IfAddMeshNode: pIntNet=%p hIf=%RX32 machineId=%p:{%s}, slot=%u\n", pIntNet, hIf, pMac, machineId, slot));
+
+    /*
+     * Validate & translate input.
+     */
+    AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(machineId, VERR_INVALID_PARAMETER);
+    PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
+    if (!pIf)
+    {
+        Log(("INTNETR0IfAddMeshNode: returns VERR_INVALID_HANDLE\n"));
+        return VERR_INVALID_HANDLE;
+    }
+
+    /*
+     * Grab the network semaphore and make the change.
+     */
+    int rc;
+    PINTNETNETWORK pNetwork = pIf->pNetwork;
+    if (pNetwork)
+    {
+        rc = RTSemFastMutexRequest(pNetwork->FastMutex);
+        if (RT_SUCCESS(rc))
+        {
+            Assert(strlen(machineId) < sizeof(pIf->machineId));   /* caller's responsibility. */
+
+            /*
+             * Allocate and initialize the interface structure.
+             */
+            PINTNETMESHNODE pMeshNode = (PINTNETMESHNODE)RTMemAllocZ(sizeof(*pMeshNode));
+            if (!pMeshNode)
+                return VERR_NO_MEMORY;
+            strcpy(pMeshNode->machineId, machineId);
+            pMeshNode->slot = slot;
+            pMeshNode->pIf = 0;
+            /*
+             * Find if the interface already exists
+             */
+            for (PINTNETIF pIfi = pIf->pNetwork->pIFs; pIfi; pIfi = pIfi->pNext)
+            {
+                if(pIfi->slot == slot && strncmp(pIfi->machineId, machineId, sizeof(machineId)) == 0)
+                    pMeshNode->pIf = pIfi;
+            }
+            // Add the mesh node
+
+            pMeshNode->pNext = pIf->meshNeighbours;
+            pIf->meshNeighbours = pMeshNode;
+                
+            rc = RTSemFastMutexRelease(pNetwork->FastMutex);
+        }
+    }
+    else
+        rc = VERR_WRONG_ORDER;
+
+    intnetR0IfRelease(pIf, pSession);
+    return rc;
+}
+
+/**
  * VMMR0 request wrapper for INTNETR0IfSetMacAddress.
  *
  * @returns see INTNETR0IfSetMacAddress.
@@ -2845,6 +2962,21 @@
 
 
 /**
+ * VMMR0 request wrapper for INTNETR0IfAddMeshNode.
+ *
+ * @returns see INTNETR0IfAddMeshNode.
+ * @param   pIntNet         The internal networking instance.
+ * @param   pSession        The caller's session.
+ * @param   pReq            The request packet.
+ */
+INTNETR0DECL(int) INTNETR0IfAddMeshNodeReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFADDMESHNODEREQ pReq)
+{
+    if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
+        return VERR_INVALID_PARAMETER;
+    return INTNETR0IfAddMeshNode(pIntNet, pReq->hIf, pSession, pReq->machineId, pReq->slot);
+}
+
+/**
  * Worker for intnetR0IfSetActive.
  *
  * This function will update the active interface count on the network and
@@ -3198,7 +3330,28 @@
         RTSemFastMutexRelease(pIntNet->FastMutex);
 
         SUPR0ObjRelease(pNetwork->pvObj, pIf->pSession);
-        pIf->pNetwork = NULL;
+        pIf->pNetwork = NULL;      
+    
+        /*
+         * Update the mesh nodes
+         */
+        for (PINTNETIF pIfi = pNetwork->pIFs; pIfi; pIfi = pIfi->pNext)
+        {
+            for (PINTNETMESHNODE neighbour = pIfi->meshNeighbours; neighbour; neighbour = neighbour->pNext)
+            {
+                if(pIf->slot == neighbour->slot && strncmp(pIf->machineId, neighbour->machineId, sizeof(neighbour->machineId)) == 0)
+                    neighbour->pIf = 0;
+            }
+        }
+        /*
+         * Free the mallocs for our neighbours list
+         */
+        PINTNETMESHNODE nextNeighbour = 0;
+        for (PINTNETMESHNODE neighbour = pIf->meshNeighbours; neighbour; neighbour = nextNeighbour)
+        {
+            PINTNETMESHNODE next = neighbour->pNext;
+            RTMemFree(neighbour);
+        }
     }
     else
         RTSemFastMutexRelease(pIntNet->FastMutex);
@@ -3276,8 +3429,10 @@
  * @param   cbSend      The size of the send buffer.
  * @param   cbRecv      The size of the receive buffer.
  * @param   phIf        Where to store the interface handle.
+ * @param   machineId   The id of machine the machine to which this interface is connected to.
+ * @param   slot        The slot to which this interface is associated with in the parent machine.
  */
-static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv, bool *pfCloseNetwork, PINTNETIFHANDLE phIf)
+static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv, bool *pfCloseNetwork, PINTNETIFHANDLE phIf, const char *machineId, unsigned slot)
 {
     LogFlow(("intnetR0NetworkCreateIf: pNetwork=%p pSession=%p cbSend=%u cbRecv=%u phIf=%p\n",
              pNetwork, pSession, cbSend, cbRecv, phIf));
@@ -3312,6 +3467,23 @@
     pIf->hIf = INTNET_HANDLE_INVALID;
     pIf->pNetwork = pNetwork;
     pIf->pSession = pSession;
+    Assert(strlen(machineId) < sizeof(pIf->machineId));   /* caller's responsibility. */
+    strcpy(pIf->machineId, machineId);
+    pIf->slot = slot;
+    pIf->meshNeighbours = 0;
+    
+    /*
+     * Update the mesh nodes
+     */
+    for (PINTNETIF pIfi = pNetwork->pIFs; pIfi; pIfi = pIfi->pNext)
+    {
+        for (PINTNETMESHNODE neighbour = pIfi->meshNeighbours; neighbour; neighbour = neighbour->pNext)
+        {
+            if(slot == neighbour->slot && strncmp(machineId, neighbour->machineId, sizeof(neighbour->machineId)) == 0)
+                neighbour->pIf = pIf;
+        }
+    }
+    
     //pIf->pvObj = NULL;
     //pIf->aAddrCache[kIntNetAddrType_Invalid] = {0};
     //pIf->aAddrCache[kIntNetAddrType_IPv4].pbEntries = NULL;
@@ -4091,13 +4263,16 @@
  * @param   cbSend          The send buffer size.
  * @param   cbRecv          The receive buffer size.
  * @param   phIf            Where to store the handle to the network interface.
+ * @param   machineId       The id of machine the machine to which this interface is connected to.
+ * @param   slot            The slot to which this interface is associated with in the parent machine.
  */
 INTNETR0DECL(int) INTNETR0Open(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork,
                                INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags,
-                               unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf)
+                               unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf,  const char* machineId,
+                               unsigned slot)
 {
-    LogFlow(("INTNETR0Open: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p\n",
-             pIntNet, pSession, pszNetwork, pszNetwork, pszTrunk, pszTrunk, enmTrunkType, fFlags, cbSend, cbRecv, phIf));
+    LogFlow(("INTNETR0Open: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p machineId=%p:{%s} slot=%u\n",
+             pIntNet, pSession, pszNetwork, pszNetwork, pszTrunk, pszTrunk, enmTrunkType, fFlags, cbSend, cbRecv, phIf, machineId, slot));
 
     /*
      * Validate input.
@@ -4110,6 +4285,10 @@
     size_t cchNetwork = pszNetworkEnd - pszNetwork;
     AssertReturn(cchNetwork, VERR_INVALID_PARAMETER);
 
+    AssertPtrReturn(machineId, VERR_INVALID_PARAMETER);
+    const char *machineIdEnd = (const char *)memchr(machineId, '\0', RTUUID_STR_LENGTH);
+    AssertReturn(machineIdEnd, VERR_INVALID_PARAMETER);
+
     if (pszTrunk)
     {
         AssertPtrReturn(pszTrunk, VERR_INVALID_PARAMETER);
@@ -4163,7 +4342,7 @@
         if (fNewNet)
             rc = intnetR0CreateNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
         if (RT_SUCCESS(rc))
-            rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, &fCloseNetwork, phIf);
+            rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, &fCloseNetwork, phIf, machineId, slot);
 
         RTSemFastMutexRelease(pIntNet->FastMutex);
 
@@ -4196,7 +4375,8 @@
     if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
         return VERR_INVALID_PARAMETER;
     return INTNETR0Open(pIntNet, pSession, &pReq->szNetwork[0], pReq->enmTrunkType, pReq->szTrunk,
-                        pReq->fFlags, pReq->cbSend, pReq->cbRecv, &pReq->hIf);
+                        pReq->fFlags, pReq->cbSend, pReq->cbRecv, &pReq->hIf, &pReq->machineId[0],
+                        pReq->slot);
 }
 
 
Index: src/VBox/Devices/Network/DrvIntNet.cpp
===================================================================
--- src/VBox/Devices/Network/DrvIntNet.cpp	(revisión: 18845)
+++ src/VBox/Devices/Network/DrvIntNet.cpp	(copia de trabajo)
@@ -89,6 +89,14 @@
     /** Set if data transmission should start immediately and deactivate
      * as late as possible. */
     bool                    fActivateEarlyDeactivateLate;
+#if defined(VBOX_WITH_NETFLT)
+    /** Set if the interface is in mesh mode */
+    bool                    fMeshMode;
+    /** The slot to which the network interface is associated with. */
+    uint32_t                slot;
+    /** The uuid of the machine in which the network interface resides */
+    char                    machineId[RTUUID_STR_LENGTH];
+#endif
 
 #ifdef VBOX_WITH_STATISTICS
     /** Profiling packet transmit runs. */
@@ -762,6 +770,7 @@
     if (!CFGMR3AreValuesValid(pCfgHandle,
                               "Network\0"
                               "Trunk\0"
+                              "MeshEnabled\0"
                               "TrunkType\0"
                               "ReceiveBufferSize\0"
                               "SendBufferSize\0"
@@ -951,6 +960,29 @@
                                 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
     if (fSharedMacOnWire)
         OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
+#if defined(VBOX_WITH_NETFLT)
+    /** @cfgm{MeshMode, boolean, false}
+     * Whether this network is in mesh mode.
+     */
+    rc = CFGMR3QueryBoolDef(pCfgHandle, "MeshMode", &(pThis->fMeshMode), false);
+    if (RT_FAILURE(rc))
+        return PDMDRV_SET_ERROR(pDrvIns, rc,
+                                N_("Configuration error: Failed to get the \"MeshMode\" value"));
+    if (pThis->fMeshMode)
+    {
+        OpenReq.fFlags |= INTNET_OPEN_FLAGS_MESH_MODE;
+        rc = CFGMR3QueryU32(pCfgHandle, "MeshNeighbours/Slot", &(pThis->slot));
+        if (RT_FAILURE(rc))
+            return PDMDRV_SET_ERROR(pDrvIns, rc,
+                                    N_("Configuration error: Failed to get the \"MeshNeighbours/Slot\" value"));
+        OpenReq.slot = pThis->slot;
+        rc = CFGMR3QueryString(pCfgHandle, "MeshNeighbours/MachineId", pThis->machineId, sizeof(pThis->machineId));
+        if (RT_FAILURE(rc))
+            return PDMDRV_SET_ERROR(pDrvIns, rc,
+                                    N_("Configuration error: Failed to get the \"MeshNeighbours/MachineId\" value"));
+        strcpy(pThis->machineId, OpenReq.machineId);
+    }
+#endif
 
     /** @cfgm{ReceiveBufferSize, uint32_t, 218 KB}
      * The size of the receive buffer.
@@ -1079,6 +1111,35 @@
 #endif
 
     /*
+     * If in mesh mode, add the mesh nodes one by one to the network interface.
+     */
+    if(pThis->fMeshMode)
+    {
+        uint32_t numMeshNodes = 0;
+        rc = CFGMR3QueryU32(pCfgHandle, "MeshNeighbours/NumMeshNeighbours", &numMeshNodes);
+        if (RT_FAILURE(rc))
+            return PDMDRV_SET_ERROR(pDrvIns, rc,
+                                    N_("Configuration error: Failed to get the \"MeshNeighbours/numMeshNodes\" value"));
+        
+        for(uint32_t i = 0; i < numMeshNodes; i++)
+        {
+            PCFGMNODE pNodeCfg = CFGMR3GetChildF (pCfgHandle, "MeshNeighbours/#%d/", i);
+            uint32_t slot;
+            char machineId[RTUUID_STR_LENGTH];
+            rc = CFGMR3QueryU32(pNodeCfg, "Slot", &slot);
+            if (RT_FAILURE(rc))
+                return PDMDRV_SET_ERROR(pDrvIns, rc,
+                                        N_("Configuration error: Failed to get a \"MeshNeighbour/Slot\" value"));
+            rc = CFGMR3QueryString(pNodeCfg, "MachineId", machineId, sizeof(machineId));
+            if (RT_FAILURE(rc))
+                return PDMDRV_SET_ERROR(pDrvIns, rc,
+                                        N_("Configuration error: Failed to get a \"MeshNeighbour/MachineId\" value"));
+            // TODO:
+            // drvIntAddMeshNode(pThis);
+        }
+    }
+
+    /*
      * Activate data transmission as early as possible
      */
     if (pThis->fActivateEarlyDeactivateLate)
Index: src/VBox/Devices/Network/testcase/tstIntNetR0.cpp
===================================================================
--- src/VBox/Devices/Network/testcase/tstIntNetR0.cpp	(revisión: 18845)
+++ src/VBox/Devices/Network/testcase/tstIntNetR0.cpp	(copia de trabajo)
@@ -448,13 +448,14 @@
      * Create two interfaces.
      */
     INTNETIFHANDLE hIf0 = INTNET_HANDLE_INVALID;
-    rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, "", 0, 1536*2 + 4, 0x8000, &hIf0);
+    char machineId[RTUUID_STR_LENGTH];
+    rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, "", 0, 1536*2 + 4, 0x8000, &hIf0, machineId, 0);
     if (RT_SUCCESS(rc))
     {
         if (hIf0 != INTNET_HANDLE_INVALID)
         {
             INTNETIFHANDLE hIf1 = INTNET_HANDLE_INVALID;
-            rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, NULL, 0, 1536*2 + 4, 0x8000, &hIf1);
+            rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, NULL, 0, 1536*2 + 4, 0x8000, &hIf1, machineId, 1);
             if (RT_SUCCESS(rc))
             {
                 if (hIf1 != INTNET_HANDLE_INVALID)
Index: src/VBox/Devices/Network/testcase/tstIntNet-1.cpp
===================================================================
--- src/VBox/Devices/Network/testcase/tstIntNet-1.cpp	(revisión: 18845)
+++ src/VBox/Devices/Network/testcase/tstIntNet-1.cpp	(copia de trabajo)
@@ -873,6 +873,10 @@
     OpenReq.fFlags = fMacSharing ? INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE : 0;
     OpenReq.cbSend = cbSend;
     OpenReq.cbRecv = cbRecv;
+
+    char machineId[RTUUID_STR_LENGTH];
+    strncpy(OpenReq.machineId, machineId, sizeof(machineId));
+    OpenReq.slot = 0;
     OpenReq.hIf = INTNET_HANDLE_INVALID;
 
     /*
Index: src/VBox/Main/include/NetworkAdapterImpl.h
===================================================================
--- src/VBox/Main/include/NetworkAdapterImpl.h	(revisión: 18845)
+++ src/VBox/Main/include/NetworkAdapterImpl.h	(copia de trabajo)
@@ -25,6 +25,7 @@
 #define ____H_NETWORKADAPTER
 
 #include "VirtualBoxBase.h"
+#include "NetworkAdapterRefImpl.h"
 
 class Machine;
 class GuestOSType;
@@ -36,14 +37,14 @@
     public INetworkAdapter
 {
 public:
-
+    typedef std::list <ComObjPtr <NetworkAdapterRef> > NetworkAdapterRefList;
     struct Data
     {
         Data()
             : mSlot (0), mEnabled (FALSE)
             , mAttachmentType (NetworkAttachmentType_Null)
             ,  mCableConnected (TRUE), mLineSpeed (0), mTraceEnabled (FALSE)
-            , mHostInterface ("") /* cannot be null */
+            , mHostInterface ("") /* cannot be null */, mMesh (FALSE)
         {}
 
         bool operator== (const Data &that) const
@@ -58,7 +59,8 @@
                     mTraceEnabled == that.mTraceEnabled &&
                     mHostInterface == that.mHostInterface &&
                     mInternalNetwork == that.mInternalNetwork &&
-                    mNATNetwork == that.mNATNetwork);
+                    mNATNetwork == that.mNATNetwork &&
+                    mMesh == that.mMesh);
         }
 
         NetworkAdapterType_T mAdapterType;
@@ -73,6 +75,8 @@
         Bstr mHostInterface;
         Bstr mInternalNetwork;
         Bstr mNATNetwork;
+        BOOL mMesh;
+        NetworkAdapterRefList mMeshNeighbours;
     };
 
     VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT (NetworkAdapter)
@@ -122,6 +126,10 @@
     STDMETHOD(COMSETTER(LineSpeed)) (ULONG aSpeed);
     STDMETHOD(COMGETTER(TraceFile)) (BSTR *aTraceFile);
     STDMETHOD(COMSETTER(TraceFile)) (IN_BSTR aTraceFile);
+    STDMETHOD(COMGETTER(MeshEnabled)) (BOOL *aEnabled);
+    STDMETHOD(COMSETTER(MeshEnabled)) (BOOL aEnabled);
+    STDMETHOD(COMGETTER(MeshNeighbours)) (ComSafeArrayOut (INetworkAdapterRef *, aNetworkAdapterRefs));
+    STDMETHOD(COMGETTER(Parent)) (IMachine **aMachine);
 
     // INetworkAdapter methods
     STDMETHOD(AttachToNAT)();
@@ -146,6 +154,7 @@
     // (ensure there is a caller and a read lock before calling them!)
 
     const Backupable <Data> &data() const { return mData; }
+    const ComObjPtr <Machine, ComWeakRef> &parent() const { return mParent; }
 
     // for VirtualBoxSupportErrorInfoImpl
     static const wchar_t *getComponentName() { return L"NetworkAdapter"; }
Index: src/VBox/Main/NetworkAdapterImpl.cpp
===================================================================
--- src/VBox/Main/NetworkAdapterImpl.cpp	(revisión: 18845)
+++ src/VBox/Main/NetworkAdapterImpl.cpp	(copia de trabajo)
@@ -682,6 +682,80 @@
     return S_OK;
 }
 
+ 
+STDMETHODIMP NetworkAdapter::COMGETTER(MeshEnabled) (BOOL *aEnabled)
+{
+    CheckComArgOutPointerValid(aEnabled);
+
+    AutoCaller autoCaller (this);
+    CheckComRCReturnRC (autoCaller.rc());
+
+    AutoReadLock alock (this);
+
+    *aEnabled = mData->mMesh;
+
+    return S_OK;
+}
+
+STDMETHODIMP NetworkAdapter::COMSETTER(MeshEnabled) (BOOL aEnabled)
+{
+    AutoCaller autoCaller (this);
+    CheckComRCReturnRC (autoCaller.rc());
+
+    /* the machine needs to be mutable */
+    Machine::AutoMutableStateDependency adep (mParent);
+    CheckComRCReturnRC (adep.rc());
+
+    AutoWriteLock alock (this);
+
+    if (mData->mMesh != aEnabled)
+    {
+        mData.backup();
+        mData->mMesh = aEnabled;
+
+        /* leave the lock before informing callbacks */
+        alock.unlock();
+
+        mParent->onNetworkAdapterChange (this);
+    }
+
+    return S_OK;
+}
+
+STDMETHODIMP NetworkAdapter::
+COMGETTER(MeshNeighbours) (ComSafeArrayOut (INetworkAdapterRef *, aNetworkAdapterRefs))
+{
+    if (ComSafeArrayOutIsNull (aNetworkAdapterRefs))
+        return E_POINTER;
+    
+    AssertReturn (mData->mMesh, E_FAIL);
+
+    AutoCaller autoCaller (this);
+    CheckComRCReturnRC (autoCaller.rc());
+
+    AutoReadLock alock (this);
+
+    SafeIfaceArray <INetworkAdapterRef> networkAdapterRefs (mData->mMeshNeighbours);
+    networkAdapterRefs.detachTo (ComSafeArrayOutArg (aNetworkAdapterRefs));
+
+    return S_OK;
+}
+
+STDMETHODIMP NetworkAdapter::COMGETTER(Parent) (IMachine **aParent)
+{
+    CheckComArgOutPointerValid(aParent);
+
+    AutoCaller autoCaller (this);
+    CheckComRCReturnRC (autoCaller.rc());
+
+    AutoReadLock alock (this);
+
+    /* mParent is const, no need to lock */
+    mParent.queryInterfaceTo (aParent);
+
+    return S_OK;
+}
+
 // INetworkAdapter methods
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -950,6 +1024,22 @@
         Bstr name = attachmentNode.stringValue ("name");
         /* name can be empty, but not null */
         ComAssertRet (!name.isNull(), E_FAIL);
+        mData->mMesh = attachmentNode.value <bool> ("mesh");
+ 
+        if(mData->mMesh)
+        {
+            Key meshNeighbourNode;
+            while (!(meshNeighbourNode = attachmentNode.findKey ("MeshNeighbour")).isNull())
+            {
+               Guid machineId = meshNeighbourNode.value<Guid>("machine");
+                ULONG aSlot = meshNeighbourNode.value <ULONG> ("slot");
+                
+                NetworkAdapterRef *networkAdapterRef = new NetworkAdapterRef();
+                networkAdapterRef->init(machineId, aSlot);
+                ComObjPtr <NetworkAdapterRef> aRef(networkAdapterRef);
+                mData->mMeshNeighbours.push_back(aRef);
+            }
+        }
 
         rc = COMSETTER(HostInterface) (name);
         CheckComRCReturnRC (rc);
@@ -1060,6 +1150,17 @@
 #if defined(VBOX_WITH_NETFLT)
             Assert (!mData->mHostInterface.isNull());
             attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
+            attachmentNode.setValue <bool> ("mesh", mData->mMesh);
+            
+            if(mData->mMesh)
+            {
+                for (NetworkAdapterRefList::const_iterator it = mData->mMeshNeighbours.begin(); it != mData->mMeshNeighbours.end(); ++ it)
+                {
+                    Key meshNeighbourNode = attachmentNode.createKey ("MeshNeighbour");
+                    meshNeighbourNode.setValue <Guid> ("machine", (*it)->machineId());
+                    meshNeighbourNode.setValue <ULONG> ("slot", (*it)->slot());
+                }
+            }
 #endif
             break;
         }
@@ -1253,4 +1354,5 @@
     LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
     mData->mMACAddress = strMAC;
 }
+
 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
Index: src/VBox/Main/Makefile.kmk
===================================================================
--- src/VBox/Main/Makefile.kmk	(revisión: 18845)
+++ src/VBox/Main/Makefile.kmk	(copia de trabajo)
@@ -295,6 +295,7 @@
 	DHCPServerRunner.cpp \
 	GuestOSTypeImpl.cpp \
 	NetworkAdapterImpl.cpp \
+    NetworkAdapterRefImpl.cpp \
 	SerialPortImpl.cpp \
 	ParallelPortImpl.cpp \
 	USBControllerImpl.cpp \
Index: src/VBox/Main/xpcom/module.cpp
===================================================================
--- src/VBox/Main/xpcom/module.cpp	(revisión: 18845)
+++ src/VBox/Main/xpcom/module.cpp	(copia de trabajo)
@@ -43,6 +43,7 @@
 #include "FramebufferImpl.h"
 #include "ProgressImpl.h"
 #include "NetworkAdapterImpl.h"
+#include "NetworkAdapterRefImpl.h"
 
 #include "SessionImpl.h"
 #include "ConsoleImpl.h"
@@ -76,6 +77,8 @@
 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SharedFolder, ISharedFolder)
 NS_DECL_CLASSINFO(RemoteDisplayInfo)
 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(RemoteDisplayInfo, IRemoteDisplayInfo)
+NS_DECL_CLASSINFO(NetworkAdapterRef)
+NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NetworkAdapterRef, INetworkAdapterRef)
 
 NS_DECL_CLASSINFO(Session)
 NS_IMPL_THREADSAFE_ISUPPORTS2_CI(Session, ISession, IInternalSessionControl)
Index: src/VBox/Main/xpcom/server.cpp
===================================================================
--- src/VBox/Main/xpcom/server.cpp	(revisión: 18845)
+++ src/VBox/Main/xpcom/server.cpp	(copia de trabajo)
@@ -204,6 +204,9 @@
 NS_DECL_CLASSINFO(NetworkAdapter)
 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NetworkAdapter, INetworkAdapter)
 
+NS_DECL_CLASSINFO(NetworkAdapterRef)
+NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NetworkAdapterRef, INetworkAdapterRef)
+
 NS_DECL_CLASSINFO(SerialPort)
 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SerialPort, ISerialPort)
 
Index: src/VBox/Main/ConsoleImpl2.cpp
===================================================================
--- src/VBox/Main/ConsoleImpl2.cpp	(revisión: 18845)
+++ src/VBox/Main/ConsoleImpl2.cpp	(copia de trabajo)
@@ -1348,8 +1348,49 @@
                 STR_FREE();
             }
         }
-
-
+#if defined(VBOX_WITH_NETFLT)
+        /*
+         * Check if mesh mode is enabled and set up the ocnfiguration if so.
+         */
+        BOOL fMesh;
+        hrc = networkAdapter->COMGETTER(MeshEnabled)(&fMesh);                       H();
+        rc = CFGMR3InsertInteger(pCfg, "MeshEnabled", (fMesh) ? 1 : 0); /* bool */  RC_CHECK();
+        if (fMesh)
+        {
+            com::SafeIfaceArray <INetworkAdapterRef> meshNeighbours;
+            networkAdapter->COMGETTER(MeshNeighbours) (ComSafeArrayAsOutParam (meshNeighbours));
+            PCFGMNODE pMeshNode = NULL;
+            PCFGMNODE pParentMesh = NULL;
+            char aNumStr[16];
+            rc = CFGMR3InsertNode(pCfg, "MeshNeighbours", &pParentMesh);            RC_CHECK();
+            rc = CFGMR3InsertInteger(pParentMesh, "NumMeshNeighbours", meshNeighbours.size());
+                                                                                    RC_CHECK();
+            ULONG aSlot;
+            hrc = networkAdapter->COMGETTER(Slot)(&aSlot);                          H();
+            ComPtr<IMachine> aMachine;
+            hrc = networkAdapter->COMGETTER(Parent)(aMachine.asOutParam());         H();
+            
+            Bstr aName;
+            hrc = aMachine->COMGETTER(Name)(aName.asOutParam());                    H();
+            rc = CFGMR3InsertInteger(pMeshNode, "Slot", aSlot);                     RC_CHECK();
+            rc = CFGMR3InsertString(pMeshNode, "MachineId", Utf8Str(aName) );       RC_CHECK();
+            
+            for (size_t a = 0; a < meshNeighbours.size(); ++ a)
+            {
+                RTStrPrintf (aNumStr, sizeof(aNumStr), "#%d", a);
+                rc = CFGMR3InsertNode(pParentMesh, aNumStr, &pMeshNode);            RC_CHECK();
+                ULONG aSlot;
+                hrc = meshNeighbours[a]->COMGETTER(Slot)(&aSlot);                   H();
+                Guid machineId;
+                hrc = meshNeighbours[a]->COMGETTER(MachineId)(machineId.asOutParam());
+                                                                                    H();
+                char bufId[RTUUID_STR_LENGTH];
+                RTUuidToStr(machineId.raw(), bufId, RTUUID_STR_LENGTH);
+                rc = CFGMR3InsertInteger(pMeshNode, "Slot", aSlot);                 RC_CHECK();
+                rc = CFGMR3InsertString(pMeshNode, "MachineId", bufId);             RC_CHECK();
+            }
+        }
+#endif
         NetworkAttachmentType_T networkAttachment;
         hrc = networkAdapter->COMGETTER(AttachmentType)(&networkAttachment);        H();
         Bstr networkName, trunkName, trunkType;
Index: src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- src/VBox/Main/idl/VirtualBox.xidl	(revisión: 18845)
+++ src/VBox/Main/idl/VirtualBox.xidl	(copia de trabajo)
@@ -10929,6 +10929,26 @@
         <desc>Intel PRO/1000 MT Server network card (82545EM).</desc>
     </const>
   </enum>
+  
+  <interface
+     name="INetworkAdapterRef" extends="$unknown"
+     uuid="2a90d238-5eb4-109b-ce14-1488a720c2dd"
+     wsmap="managed"
+     >
+    <desc>
+        Represents a reference to a virtual network adapter using two attributes:
+        the machine to which the network adpater is attached, and the slot in
+        which the network adapter is attached in that machine. It's used instead
+        of INetworkAdapter to reference NetworkAdapters that might not have been
+        created yet.
+    </desc>
+    <attribute name="machineId" type="uuid" readonly="yes">
+      <desc>The machine ID to which this network interface is attached to.</desc>
+    </attribute>
+    <attribute name="slot" type="unsigned long" readonly="yes">
+      <desc>The slot in which the network adapter is attached to.</desc>
+    </attribute>
+  </interface>
 
   <interface
      name="INetworkAdapter" extends="$unknown"
@@ -11026,6 +11046,29 @@
       </desc>
     </attribute>
 
+ 
+    <attribute name="meshEnabled" type="boolean">
+      <desc>
+        Flag whether this network will be mesh, meaning that instead of everyone
+        being neighbours, a given network interface is connected to a subset of
+        other network interfaces, forming a mesh network.
+      </desc>
+    </attribute>
+
+    <attribute name="parent" type="IMachine" readonly="yes">
+      <desc>
+        Associated parent object.
+      </desc>
+    </attribute>
+
+    <attribute name="meshNeighbours" type="INetworkAdapterRef" safearray="yes" readonly="yes">
+      <desc>
+        List of all the other network adapters connected to this one in a mesh
+        network. In order to call get the list, the network adapter must be
+        in mesh mode or else it will return E_FAIL.
+      </desc>
+    </attribute>
+
     <method name="attachToNAT">
       <desc>
         Attach the network adapter to the Network Address Translation (NAT) interface.
_______________________________________________
vbox-dev mailing list
[email protected]
http://vbox.innotek.de/mailman/listinfo/vbox-dev

Reply via email to