[TDILIB, IPHLPAPI, WSHTCPIP]
authorCameron Gutman <aicommander@gmail.com>
Sat, 16 Jan 2010 00:05:15 +0000 (00:05 +0000)
committerCameron Gutman <aicommander@gmail.com>
Sat, 16 Jan 2010 00:05:15 +0000 (00:05 +0000)
 - Move the TDI stuff from iphlpapi to a shared library called tdilib
[IP]
 - Implement tcpip side of IP_HDRINCL
[PSDK, WSHTCPIP, WSHIRDA]
 - Fix definition of WSHGetSocketInformation
[PSDK]
 - Add AO_OPTION_* defines
[WSHTCPIP]
 - Request notifications for bind also
 - Implement WSHSetSocketInformation
[MSAFD]
 - Implement event notifications (bonus: fixes a memory leak on socket closure due to unfreed helper context)
 - Store TdiConnectionHandle the same way we store TdiAddressHandle
 - Half-plement WSPSetSockOpt
 - Fix WSPGetSockOpt
[TCPIP]
 - Handle AO_OPTION_TTL, AO_OPTION_IP_DONTFRAGMENT (not working yet), AO_OPTION_BROADCAST (not working yet), and AO_OPTION_IP_HDRINCL
 - Add new members of ADDRESS_FILE for the preceding AO options
[AFD]
 - Return the connection handle in the Information of the IOSB (same as we do with the address file handle)
[GENERAL]
 - Tracert works now

svn path=/branches/aicom-network-branch/; revision=45093

21 files changed:
dll/win32/iphlpapi/ifenum_reactos.c
dll/win32/iphlpapi/iphlpapi.rbuild
dll/win32/iphlpapi/iphlpapi_private.h
dll/win32/msafd/misc/dllmain.c
dll/win32/msafd/misc/stubs.c
dll/win32/wshirda/wshirda.c
dll/win32/wshtcpip/wshtcpip.c
dll/win32/wshtcpip/wshtcpip.h
dll/win32/wshtcpip/wshtcpip.rbuild
drivers/network/afd/afd/connect.c
drivers/network/tcpip/include/titypes.h
drivers/network/tcpip/tcpip/ainfo.c
drivers/network/tcpip/tcpip/fileobjs.c
include/psdk/tcpioctl.h
include/psdk/wsahelp.h
lib/drivers/ip/transport/datagram/datagram.c
lib/lib.rbuild
lib/tdilib/enum.c [new file with mode: 0644]
lib/tdilib/handle.c [new file with mode: 0644]
lib/tdilib/tdilib.h [new file with mode: 0644]
lib/tdilib/tdilib.rbuild [new file with mode: 0644]

index 55c5c10..8eec8a7 100644 (file)
@@ -45,9 +45,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
 
-/* Globals */
-const PWCHAR TcpFileName = L"\\Device\\Tcp";
-
 /* Functions */
 
 /* I'm a bit skittish about maintaining this info in memory, as I'd rather
@@ -64,171 +61,6 @@ void interfaceMapFree(void)
     /* Ditto. */
 }
 
-NTSTATUS openTcpFile(PHANDLE tcpFile) {
-    UNICODE_STRING fileName;
-    OBJECT_ATTRIBUTES objectAttributes;
-    IO_STATUS_BLOCK ioStatusBlock;
-    NTSTATUS status;
-
-    TRACE("called.\n");
-
-    /* Shamelessly ripped from CreateFileW */
-    RtlInitUnicodeString( &fileName, TcpFileName );
-
-    InitializeObjectAttributes( &objectAttributes,
-                                &fileName,
-                                OBJ_CASE_INSENSITIVE,
-                                NULL,
-                                NULL );
-
-    status = ZwCreateFile( tcpFile,
-                           SYNCHRONIZE | GENERIC_EXECUTE |
-                           GENERIC_READ | GENERIC_WRITE,
-                           &objectAttributes,
-                           &ioStatusBlock,
-                           NULL,
-                           FILE_ATTRIBUTE_NORMAL,
-                           FILE_SHARE_READ | FILE_SHARE_WRITE,
-                           FILE_OPEN_IF,
-                           FILE_SYNCHRONOUS_IO_NONALERT,
-                           0,
-                           0 );
-
-    /* String does not need to be freed: it points to the constant
-     * string we provided */
-
-    if (!NT_SUCCESS(status)) {
-        ERR("openTcpFile for <%wZ> failed: 0x%lx\n", &fileName, status);
-        *tcpFile = INVALID_HANDLE_VALUE;
-    }
-
-    return status;
-}
-
-void closeTcpFile( HANDLE h ) {
-    TRACE("called.\n");
-    ASSERT(h != INVALID_HANDLE_VALUE);
-    ZwClose( h );
-}
-
-/* A generic thing-getting function which interacts in the right way with
- * TDI.  This may seem oblique, but I'm using it to reduce code and hopefully
- * make this thing easier to debug.
- *
- * The things returned can be any of:
- *   TDIEntityID
- *   TDIObjectID
- *   IFEntry
- *   IPSNMPInfo
- *   IPAddrEntry
- *   IPInterfaceInfo
- */
-NTSTATUS tdiGetSetOfThings( HANDLE tcpFile,
-                            DWORD toiClass,
-                            DWORD toiType,
-                            DWORD toiId,
-                            DWORD teiEntity,
-                           DWORD teiInstance,
-                            DWORD fixedPart,
-                            DWORD entrySize,
-                            PVOID *tdiEntitySet,
-                            PDWORD numEntries ) {
-    TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
-    PVOID entitySet = 0;
-    NTSTATUS status = STATUS_SUCCESS;
-    DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES,
-        arraySize = entrySize * MAX_TDI_ENTITIES;
-
-    TRACE("TdiGetSetOfThings(tcpFile %x,toiClass %x,toiType %x,toiId %x,"
-          "teiEntity %x,fixedPart %d,entrySize %d)\n",
-          (int)tcpFile,
-          (int)toiClass,
-          (int)toiType,
-          (int)toiId,
-          (int)teiEntity,
-          (int)fixedPart,
-          (int)entrySize );
-
-    req.ID.toi_class                = toiClass;
-    req.ID.toi_type                 = toiType;
-    req.ID.toi_id                   = toiId;
-    req.ID.toi_entity.tei_entity    = teiEntity;
-    req.ID.toi_entity.tei_instance  = teiInstance;
-
-    /* There's a subtle problem here...
-     * If an interface is added at this exact instant, (as if by a PCMCIA
-     * card insertion), the array will still not have enough entries after
-     * have allocated it after the first DeviceIoControl call.
-     *
-     * We'll get around this by repeating until the number of interfaces
-     * stabilizes.
-     */
-    do {
-        assert( !entitySet ); /* We must not have an entity set allocated */
-        status = DeviceIoControl( tcpFile,
-                                  IOCTL_TCP_QUERY_INFORMATION_EX,
-                                  &req,
-                                  sizeof(req),
-                                  0,
-                                  0,
-                                  &allocationSizeForEntityArray,
-                                  NULL );
-
-        if(!NT_SUCCESS(status))
-        {
-            ERR("IOCTL Failed\n");
-            return STATUS_UNSUCCESSFUL;
-        }
-
-        arraySize = allocationSizeForEntityArray;
-        entitySet = HeapAlloc( GetProcessHeap(), 0, arraySize );
-
-        if( !entitySet ) {
-            status = STATUS_INSUFFICIENT_RESOURCES;
-            WARN("TdiGetSetOfThings() => %08x\n", (int)status);
-            return status;
-        }
-
-        status = DeviceIoControl( tcpFile,
-                                  IOCTL_TCP_QUERY_INFORMATION_EX,
-                                  &req,
-                                  sizeof(req),
-                                  entitySet,
-                                  arraySize,
-                                  &allocationSizeForEntityArray,
-                                  NULL );
-
-        /* This is why we have the loop -- we might have added an adapter */
-        if( arraySize == allocationSizeForEntityArray )
-            break;
-
-        HeapFree( GetProcessHeap(), 0, entitySet );
-        entitySet = 0;
-
-        if(!status)
-        {
-            WARN("IOCTL Failed\n");
-            return STATUS_UNSUCCESSFUL;
-        }
-
-        WARN("TdiGetSetOfThings(): Array changed size: %d -> %d.\n",
-               arraySize, allocationSizeForEntityArray );
-    } while( TRUE ); /* We break if the array we received was the size we
-                      * expected.  Therefore, we got here because it wasn't */
-
-    *numEntries = (arraySize - fixedPart) / entrySize;
-    *tdiEntitySet = entitySet;
-
-    WARN("TdiGetSetOfThings() => Success: %d things @ %08x\n",
-           (int)*numEntries, (int)entitySet);
-
-    return STATUS_SUCCESS;
-}
-
-VOID tdiFreeThingSet( PVOID things ) {
-    HeapFree( GetProcessHeap(), 0, things );
-}
-
 NTSTATUS tdiGetMibForIfEntity
 ( HANDLE tcpFile, TDIEntityID *ent, IFEntrySafelySized *entry ) {
     TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
@@ -283,33 +115,6 @@ NTSTATUS tdiGetMibForIfEntity
     return STATUS_SUCCESS;
 }
 
-NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile,
-                            TDIEntityID **entitySet,
-                            PDWORD numEntities ) {
-    NTSTATUS status = tdiGetSetOfThings( tcpFile,
-                                         INFO_CLASS_GENERIC,
-                                         INFO_TYPE_PROVIDER,
-                                         ENTITY_LIST_ID,
-                                         GENERIC_ENTITY,
-                                        0,
-                                         0,
-                                         sizeof(TDIEntityID),
-                                         (PVOID *)entitySet,
-                                         numEntities );
-    if( NT_SUCCESS(status) ) {
-        int i;
-
-        for( i = 0; i < *numEntities; i++ ) {
-            TRACE("%-4d: %04x:%08x\n",
-                   i,
-                   (*entitySet)[i].tei_entity,
-                   (*entitySet)[i].tei_instance );
-        }
-    }
-
-    return status;
-}
-
 BOOL isInterface( TDIEntityID *if_maybe ) {
     return
         if_maybe->tei_entity == IF_ENTITY;
index 6582639..3ef209f 100644 (file)
@@ -3,12 +3,14 @@
        <include base="iphlpapi">.</include>
        <include base="ReactOS">include/reactos/wine</include>
         <include base="dhcp">include</include>
+       <include base="tdilib">.</include>
        <library>wine</library>
        <library>ntdll</library>
        <library>kernel32</library>
        <library>advapi32</library>
        <library>ws2_32</library>
        <library>dhcpcsvc</library>
+       <library>tdilib</library>
        <file>dhcp_reactos.c</file>
        <file>ifenum_reactos.c</file>
        <file>ipstats_reactos.c</file>
index 4210198..90efff7 100644 (file)
@@ -37,6 +37,8 @@
 #include "ddk/tdiinfo.h"
 #include "tcpioctl.h"
 
+#include "tdilib.h"
+
 #ifndef ETH_ALEN
 #define ETH_ALEN 6
 #endif
@@ -120,20 +122,9 @@ typedef enum _IPHLPAddrType {
 } IPHLPAddrType;
 
 /** Prototypes **/
-NTSTATUS openTcpFile(PHANDLE tcpFile);
-VOID closeTcpFile(HANDLE tcpFile);
-NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile, TDIEntityID **entitySet,
-                           PDWORD numEntities );
-NTSTATUS tdiGetSetOfThings( HANDLE tcpFile, DWORD toiClass, DWORD toiType,
-                           DWORD toiId, DWORD teiEntity, DWORD teiInstance,
-                           DWORD fixedPart,
-                           DWORD entrySize, PVOID *tdiEntitySet,
-                           PDWORD numEntries );
-VOID tdiFreeThingSet( PVOID things );
 NTSTATUS getNthIpEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent );
 NTSTATUS tdiGetIpAddrsForIpEntity( HANDLE tcpFile, TDIEntityID *ent,
                                   IPAddrEntry **addrs, PDWORD numAddrs );
-
 int GetLongestChildKeyName( HANDLE RegHandle );
 LONG OpenChildKeyRead( HANDLE RegHandle,
                       PWCHAR ChildKeyName,
index 9c10829..d01a97e 100644 (file)
@@ -426,6 +426,22 @@ WSPCloseSocket(IN SOCKET Handle,
     /* Get the Socket Structure associate to this Socket*/
     Socket = GetSocketStructure(Handle);
 
+    if (Socket->HelperEvents & WSH_NOTIFY_CLOSE)
+    {
+        Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
+                                               Socket->Handle,
+                                               Socket->TdiAddressHandle,
+                                               Socket->TdiConnectionHandle,
+                                               WSH_NOTIFY_CLOSE);
+
+        if (Status)
+        {
+            if (lpErrno) *lpErrno = Status;
+            NtClose(SockEvent);
+            return SOCKET_ERROR;
+        }
+    }
+
     /* If a Close is already in Process, give up */
     if (Socket->SharedData.State == SocketClosed)
     {
@@ -517,12 +533,11 @@ WSPCloseSocket(IN SOCKET Handle,
             if (Status == STATUS_PENDING)
             {
                 WaitForSingleObject(SockEvent, INFINITE);
+                Status = IoStatusBlock.Status;
             }
         }
     }
 
-    /* FIXME: We should notify the Helper DLL of WSH_NOTIFY_CLOSE */
-
     /* Cleanup Time! */
     Socket->HelperContext = NULL;
     Socket->SharedData.AsyncDisabledEvents = -1;
@@ -635,6 +650,21 @@ WSPBind(SOCKET Handle,
 
     NtClose( SockEvent );
 
+    if (Status == STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_BIND))
+    {
+        Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
+                                               Socket->Handle,
+                                               Socket->TdiAddressHandle,
+                                               Socket->TdiConnectionHandle,
+                                               WSH_NOTIFY_BIND);
+
+        if (Status)
+        {
+            if (lpErrno) *lpErrno = Status;
+            return SOCKET_ERROR;
+        }
+    }
+
     return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
 }
 
@@ -694,6 +724,21 @@ WSPListen(SOCKET Handle,
 
     NtClose( SockEvent );
 
+    if (Status == STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_LISTEN))
+    {
+        Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
+                                               Socket->Handle,
+                                               Socket->TdiAddressHandle,
+                                               Socket->TdiConnectionHandle,
+                                               WSH_NOTIFY_LISTEN);
+
+        if (Status)
+        {
+           if (lpErrno) *lpErrno = Status;
+           return SOCKET_ERROR;
+        }
+    }
+
     return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
 }
 
@@ -1277,6 +1322,21 @@ WSPAccept(SOCKET Handle,
 
     AFD_DbgPrint(MID_TRACE,("Socket %x\n", AcceptSocket));
 
+    if (Status == STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_ACCEPT))
+    {
+        Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
+                                               Socket->Handle,
+                                               Socket->TdiAddressHandle,
+                                               Socket->TdiConnectionHandle,
+                                               WSH_NOTIFY_ACCEPT);
+
+        if (Status)
+        {
+            if (lpErrno) *lpErrno = Status;
+            return INVALID_SOCKET;
+        }
+    }
+
     *lpErrno = 0;
 
     /* Return Socket */
@@ -1433,6 +1493,8 @@ WSPConnect(SOCKET Handle,
         Status = IOSB.Status;
     }
 
+    Socket->TdiConnectionHandle = (HANDLE)IOSB.Information;
+
     /* Get any pending connect data */
     if (lpCalleeData != NULL)
     {
@@ -1464,6 +1526,35 @@ WSPConnect(SOCKET Handle,
 
     NtClose( SockEvent );
 
+    if (Status == STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_CONNECT))
+    {
+        Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
+                                               Socket->Handle,
+                                               Socket->TdiAddressHandle,
+                                               Socket->TdiConnectionHandle,
+                                               WSH_NOTIFY_CONNECT);
+
+        if (Status)
+        {
+            if (lpErrno) *lpErrno = Status;
+            return SOCKET_ERROR;
+        }
+    }
+    else if (Status != STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_CONNECT_ERROR))
+    {
+        Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
+                                               Socket->Handle,
+                                               Socket->TdiAddressHandle,
+                                               Socket->TdiConnectionHandle,
+                                               WSH_NOTIFY_CONNECT_ERROR);
+
+        if (Status)
+        {
+            if (lpErrno) *lpErrno = Status;
+            return SOCKET_ERROR;
+        }
+    }
+
     return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
 }
 int
@@ -1850,11 +1941,52 @@ WSPGetSockOpt(IN SOCKET Handle,
 
         case IPPROTO_TCP: /* FIXME */
         default:
-            *lpErrno = WSAEINVAL;
-            return SOCKET_ERROR;
+            *lpErrno = Socket->HelperData->WSHGetSocketInformation(Socket->HelperContext,
+                                                                   Handle,
+                                                                   Socket->TdiAddressHandle,
+                                                                   Socket->TdiConnectionHandle,
+                                                                   Level,
+                                                                   OptionName,
+                                                                   OptionValue,
+                                                                   (LPINT)OptionLength);
+            return (*lpErrno == 0) ? 0 : SOCKET_ERROR;
     }
 }
 
+INT
+WSPAPI
+WSPSetSockOpt(
+    IN  SOCKET s,
+    IN  INT level,
+    IN  INT optname,
+    IN  CONST CHAR FAR* optval,
+    IN  INT optlen,
+    OUT LPINT lpErrno)
+{
+    PSOCKET_INFORMATION Socket;
+
+    /* Get the Socket Structure associate to this Socket*/
+    Socket = GetSocketStructure(s);
+    if (Socket == NULL)
+    {
+        *lpErrno = WSAENOTSOCK;
+        return SOCKET_ERROR;
+    }
+
+
+    /* FIXME: We should handle some cases here */
+
+
+    *lpErrno = Socket->HelperData->WSHSetSocketInformation(Socket->HelperContext,
+                                                           s,
+                                                           Socket->TdiAddressHandle,
+                                                           Socket->TdiConnectionHandle,
+                                                           level,
+                                                           optname,
+                                                           (PCHAR)optval,
+                                                           optlen);
+    return (*lpErrno == 0) ? 0 : SOCKET_ERROR;
+}
 
 /*
  * FUNCTION: Initialize service provider for a client
index 6de00a6..5a9da71 100644 (file)
@@ -100,22 +100,6 @@ WSPJoinLeaf(
     return (SOCKET)0;
 }
 
-
-INT
-WSPAPI
-WSPSetSockOpt(
-    IN  SOCKET s,
-    IN  INT level,
-    IN  INT optname,
-    IN  CONST CHAR FAR* optval,
-    IN  INT optlen,
-    OUT LPINT lpErrno)
-{
-    UNIMPLEMENTED
-
-    return 0;
-}
-
 INT
 WSPAPI
 WSPStringToAddress(
index 1ee4824..eee977e 100644 (file)
@@ -91,7 +91,7 @@ WSHGetSocketInformation(
     IN  INT Level,
     IN  INT OptionName,
     OUT PCHAR OptionValue,
-    OUT INT OptionLength)
+    OUT LPINT OptionLength)
 {
     UNIMPLEMENTED
 
index 91c7fba..c585128 100644 (file)
@@ -156,9 +156,39 @@ WSHGetSockaddrType(
     return NO_ERROR;
 }
 
-
-
-
+UINT
+GetAddressOption(INT Level, INT OptionName)
+{
+    switch (Level)
+    {
+       case IPPROTO_IP:
+          switch (OptionName)
+          {
+             case IP_TTL:
+                return AO_OPTION_TTL;
+
+             case IP_DONTFRAGMENT:
+                return AO_OPTION_IP_DONTFRAGMENT;
+
+#if 0
+             case IP_RECEIVE_BROADCAST:
+                return AO_OPTION_BROADCAST;
+#endif
+
+             case IP_HDRINCL:
+                return AO_OPTION_IP_HDRINCL;
+
+             default:
+                DPRINT1("Unknown option name for IPPROTO_IP: %d\n", OptionName);
+                return 0;
+          }
+          break;
+
+       default:
+          DPRINT1("Unknown level: %d\n", Level);
+          return 0;
+    }
+}
 
 INT
 EXPORT
@@ -170,7 +200,7 @@ WSHGetSocketInformation(
     IN  INT Level,
     IN  INT OptionName,
     OUT PCHAR OptionValue,
-    OUT INT OptionLength)
+    OUT LPINT OptionLength)
 {
     UNIMPLEMENTED
 
@@ -309,6 +339,37 @@ WSHJoinLeaf(
     return NO_ERROR;
 }
 
+INT
+SendRequest(
+    IN PVOID Request,
+    IN DWORD RequestSize,
+    IN DWORD IOCTL)
+{
+    BOOLEAN Status;
+    HANDLE TcpCC;
+    DWORD BytesReturned;
+
+    if (openTcpFile(&TcpCC) != STATUS_SUCCESS)
+        return WSAEINVAL;
+
+    Status = DeviceIoControl(TcpCC,
+                             IOCTL,
+                             Request,
+                             RequestSize,
+                             NULL,
+                             0,
+                             &BytesReturned,
+                             NULL);
+
+    closeTcpFile(TcpCC);
+
+    DPRINT("DeviceIoControl: %d\n", ((Status == TRUE) ? 0 : GetLastError()));
+
+    if (!Status)
+        return WSAEINVAL;
+
+    return NO_ERROR;
+}
 
 INT
 EXPORT
@@ -319,15 +380,86 @@ WSHNotify(
     IN  HANDLE TdiConnectionObjectHandle,
     IN  DWORD NotifyEvent)
 {
+    PSOCKET_CONTEXT Context = HelperDllSocketContext;
+    NTSTATUS Status;
+    HANDLE TcpCC;
+    TDIEntityID *EntityIDs;
+    DWORD EntityCount, i;
+    PQUEUED_REQUEST QueuedRequest, NextQueuedRequest;
+
     switch (NotifyEvent)
     {
         case WSH_NOTIFY_CLOSE:
-        HeapFree(GetProcessHeap(), 0, HelperDllSocketContext);
-        break;
+            DPRINT("WSHNotify: WSH_NOTIFY_CLOSE\n");
+            QueuedRequest = Context->RequestQueue;
+            while (QueuedRequest)
+            {
+                NextQueuedRequest = QueuedRequest->Next;
+
+                HeapFree(GetProcessHeap(), 0, QueuedRequest->Info);
+                HeapFree(GetProcessHeap(), 0, QueuedRequest);
+
+                QueuedRequest = NextQueuedRequest;
+            }
+            HeapFree(GetProcessHeap(), 0, HelperDllSocketContext);
+            break;
+
+
+        case WSH_NOTIFY_BIND:
+            DPRINT("WSHNotify: WSH_NOTIFY_BIND\n");
+            Status = openTcpFile(&TcpCC);
+            if (Status != STATUS_SUCCESS)
+                return WSAEINVAL;
+
+            Status = tdiGetEntityIDSet(TcpCC,
+                                       &EntityIDs,
+                                       &EntityCount);
 
+            closeTcpFile(TcpCC);
+
+            if (Status != STATUS_SUCCESS)
+                return WSAEINVAL;
+
+            for (i = 0; i < EntityCount; i++)
+            {
+                if (EntityIDs[i].tei_entity == CO_TL_ENTITY ||
+                    EntityIDs[i].tei_entity == CL_TL_ENTITY ||
+                    EntityIDs[i].tei_entity == ER_ENTITY)
+                {
+                    Context->AddrFileInstance = EntityIDs[i].tei_instance;
+                    Context->AddrFileEntityType = EntityIDs[i].tei_entity;
+                }
+            }
+
+            DPRINT("Instance: %x Type: %x\n", Context->AddrFileInstance, Context->AddrFileEntityType);
+
+            tdiFreeThingSet(EntityIDs);
+
+            Context->SocketState = SocketStateBound;
+
+            QueuedRequest = Context->RequestQueue;
+            while (QueuedRequest)
+            {
+                QueuedRequest->Info->ID.toi_entity.tei_entity = Context->AddrFileEntityType;
+                QueuedRequest->Info->ID.toi_entity.tei_instance = Context->AddrFileInstance;
+
+                SendRequest(QueuedRequest->Info,
+                            sizeof(*QueuedRequest->Info) + QueuedRequest->Info->BufferSize,
+                            IOCTL_TCP_SET_INFORMATION_EX);
+
+                NextQueuedRequest = QueuedRequest->Next;
+
+                HeapFree(GetProcessHeap(), 0, QueuedRequest->Info);
+                HeapFree(GetProcessHeap(), 0, QueuedRequest);
+
+                QueuedRequest = NextQueuedRequest;
+            }
+            Context->RequestQueue = NULL;
+            break;
+            
         default:
-        DPRINT1("Unwanted notification received! (%d)\n", NotifyEvent);
-        break;
+            DPRINT1("Unwanted notification received! (%d)\n", NotifyEvent);
+            break;
     }
 
     return NO_ERROR;
@@ -450,7 +582,7 @@ WSHOpenSocket2(
 
     /* Setup a socket context area */
 
-    Context = HeapAlloc(GetProcessHeap(), 0, sizeof(SOCKET_CONTEXT));
+    Context = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SOCKET_CONTEXT));
     if (!Context) {
         RtlFreeUnicodeString(TransportDeviceName);
         return WSAENOBUFS;
@@ -460,14 +592,14 @@ WSHOpenSocket2(
     Context->SocketType    = *SocketType;
     Context->Protocol      = *Protocol;
     Context->Flags         = Flags;
+    Context->SocketState   = SocketStateCreated;
 
     *HelperDllSocketContext = Context;
-    *NotificationEvents = WSH_NOTIFY_CLOSE;
+    *NotificationEvents = WSH_NOTIFY_CLOSE | WSH_NOTIFY_BIND;
 
     return NO_ERROR;
 }
 
-
 INT
 EXPORT
 WSHSetSocketInformation(
@@ -480,9 +612,74 @@ WSHSetSocketInformation(
     IN  PCHAR OptionValue,
     IN  INT OptionLength)
 {
-    UNIMPLEMENTED
+    PSOCKET_CONTEXT Context = HelperDllSocketContext;
+    UINT RealOptionName;
+    INT Status;
+    PTCP_REQUEST_SET_INFORMATION_EX Info;
+    PQUEUED_REQUEST Queued, NextQueued;
 
-    return NO_ERROR;
+    DPRINT("WSHSetSocketInformation\n");
+
+    /* FIXME: We only handle address file object here */
+
+    RealOptionName = GetAddressOption(Level, OptionName);
+    if (!RealOptionName)
+        return WSAEINVAL;
+
+    Info = HeapAlloc(GetProcessHeap(), 0, sizeof(*Info) + OptionLength);
+    if (!Info)
+        return WSAENOBUFS;
+
+    Info->ID.toi_entity.tei_entity = Context->AddrFileEntityType;
+    Info->ID.toi_entity.tei_instance = Context->AddrFileInstance;
+    Info->ID.toi_class = INFO_CLASS_PROTOCOL;
+    Info->ID.toi_type = INFO_TYPE_ADDRESS_OBJECT;
+    Info->ID.toi_id = RealOptionName;
+    Info->BufferSize = OptionLength;
+    memcpy(Info->Buffer, OptionValue, OptionLength);
+
+    if (Context->SocketState == SocketStateCreated)
+    {
+        if (Context->RequestQueue)
+        {
+            Queued = Context->RequestQueue;
+            while ((NextQueued = Queued->Next))
+            {
+               Queued = NextQueued;
+            }
+
+            Queued->Next = HeapAlloc(GetProcessHeap(), 0, sizeof(QUEUED_REQUEST));
+            if (!Queued->Next)
+            {
+                HeapFree(GetProcessHeap(), 0, Info);
+                return WSAENOBUFS;
+            }
+
+            NextQueued = Queued->Next;
+            NextQueued->Next = NULL;
+            NextQueued->Info = Info;
+        }
+        else
+        {
+            Context->RequestQueue = HeapAlloc(GetProcessHeap(), 0, sizeof(QUEUED_REQUEST));
+            if (!Context->RequestQueue)
+            {
+                HeapFree(GetProcessHeap(), 0, Info);
+                return WSAENOBUFS;
+            }
+
+            Context->RequestQueue->Next = NULL;
+            Context->RequestQueue->Info = Info;
+        }
+
+        return 0;
+    }
+
+    Status = SendRequest(Info, sizeof(*Info) + Info->BufferSize, IOCTL_TCP_SET_INFORMATION_EX);
+
+    HeapFree(GetProcessHeap(), 0, Info);
+
+    return Status;
 }
 
 
index a9ad8e2..6a3ece0 100644 (file)
@@ -9,6 +9,10 @@
 
 #define WIN32_NO_STATUS
 #include <wsahelp.h>
+#include <tdiinfo.h>
+#include <tcpioctl.h>
+#include <tdilib.h>
+#include <ws2tcpip.h>
 #include <rtlfuncs.h>
 
 #define EXPORT WINAPI
 #define DD_UDP_DEVICE_NAME      L"\\Device\\Udp"
 #define DD_RAW_IP_DEVICE_NAME   L"\\Device\\RawIp"
 
+typedef enum _SOCKET_STATE {
+    SocketStateCreated,
+    SocketStateBound,
+    SocketStateListening,
+    SocketStateConnected
+} SOCKET_STATE, *PSOCKET_STATE;
+
+typedef struct _QUEUED_REQUEST {
+    PTCP_REQUEST_SET_INFORMATION_EX Info;
+    PVOID Next;
+} QUEUED_REQUEST, *PQUEUED_REQUEST;
 
 typedef struct _SOCKET_CONTEXT {
     INT AddressFamily;
     INT SocketType;
     INT Protocol;
     DWORD Flags;
+    DWORD AddrFileEntityType;
+    DWORD AddrFileInstance;
+    SOCKET_STATE SocketState;
+    PQUEUED_REQUEST RequestQueue;
 } SOCKET_CONTEXT, *PSOCKET_CONTEXT;
 
 #endif /* __WSHTCPIP_H */
index 84e3cae..c224d5f 100644 (file)
@@ -3,9 +3,11 @@
 <module name="wshtcpip" type="win32dll" entrypoint="0" baseaddress="${BASEADDRESS_WSHTCPIP}" installbase="system32" installname="wshtcpip.dll" unicode="yes">
        <importlibrary definition="wshtcpip.spec" />
        <include base="wshtcpip">.</include>
+       <include base="tdilib">.</include>
        <library>ntdll</library>
        <library>kernel32</library>
        <library>ws2_32</library>
+       <library>tdilib</library>
        <file>wshtcpip.c</file>
        <file>wshtcpip.rc</file>
 </module>
index 7ee3aba..c49e651 100644 (file)
@@ -302,7 +302,7 @@ static NTSTATUS NTAPI StreamSocketConnectComplete
        NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
        AFD_DbgPrint(MID_TRACE,("Completing connect %x\n", NextIrp));
        NextIrp->IoStatus.Status = Status;
-       NextIrp->IoStatus.Information = 0;
+       NextIrp->IoStatus.Information = NT_SUCCESS(Status) ? ((ULONG_PTR)FCB->Connection.Handle) : 0;
        if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
         (void)IoSetCancelRoutine(NextIrp, NULL);
        IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
index 5a921e4..fb8ec77 100644 (file)
@@ -136,6 +136,9 @@ typedef struct _ADDRESS_FILE {
     USHORT Protocol;                      /* Protocol number */
     USHORT Port;                          /* Network port (network byte order) */
     UCHAR TTL;                            /* Time to live stored in packets sent from this address file */
+    UINT DF;                              /* Don't fragment */
+    UINT BCast;                           /* Receive broadcast packets */
+    UINT HeaderIncl;                      /* Include header in RawIP packets */
     WORK_QUEUE_ITEM WorkItem;             /* Work queue item handle */
     DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine for delete request */
     PVOID Context;                        /* Delete request context */
index 0c1b11e..0317202 100644 (file)
@@ -13,21 +13,50 @@ TDI_STATUS SetAddressFileInfo(TDIObjectID *ID,
                               PVOID Buffer,
                               UINT BufferSize)
 {
-    //KIRQL OldIrql;
+    KIRQL OldIrql;
 
     switch (ID->toi_id)
     {
-#if 0
       case AO_OPTION_TTL:
-         if (BufferSize < sizeof(UCHAR))
+         if (BufferSize < sizeof(UINT))
              return TDI_INVALID_PARAMETER;
 
-         KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+         LockObject(AddrFile, &OldIrql);
          AddrFile->TTL = *((PUCHAR)Buffer);
-         KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+         UnlockObject(AddrFile, OldIrql);
 
          return TDI_SUCCESS;
-#endif
+
+      case AO_OPTION_IP_DONTFRAGMENT:
+         if (BufferSize < sizeof(UINT))
+             return TDI_INVALID_PARAMETER;
+
+         LockObject(AddrFile, &OldIrql);
+         AddrFile->DF = *((PUINT)Buffer);
+         UnlockObject(AddrFile, OldIrql);
+
+         return TDI_SUCCESS;
+
+      case AO_OPTION_BROADCAST:
+         if (BufferSize < sizeof(UINT))
+             return TDI_INVALID_PARAMETER;
+
+         LockObject(AddrFile, &OldIrql);
+         AddrFile->BCast = *((PUINT)Buffer);
+         UnlockObject(AddrFile, OldIrql);
+
+         return TDI_SUCCESS;
+
+      case AO_OPTION_IP_HDRINCL:
+         if (BufferSize < sizeof(UINT))
+             return TDI_INVALID_PARAMETER;
+
+         LockObject(AddrFile, &OldIrql);
+         AddrFile->HeaderIncl = *((PUINT)Buffer);
+         UnlockObject(AddrFile, OldIrql);
+
+         return TDI_SUCCESS;
+
       default:
          DbgPrint("Unimplemented option %x\n", ID->toi_id);
 
index 62ca63c..bd7968e 100644 (file)
@@ -244,15 +244,16 @@ NTSTATUS FileOpenAddress(
     return STATUS_INSUFFICIENT_RESOURCES;
   }
 
-  TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
-
   RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
 
   AddrFile->RefCount = 1;
   AddrFile->Free = AddrFileFree;
 
-  /* Set our default TTL */
+  /* Set our default options */
   AddrFile->TTL = 128;
+  AddrFile->DF = 0;
+  AddrFile->BCast = 1;
+  AddrFile->HeaderIncl = 1;
 
   /* Make sure address is a local unicast address or 0 */
   /* FIXME: IPv4 only */
index 033ec11..28d0f35 100644 (file)
 #define IP_INTFC_INFO_ID                0x103
 #define MAX_PHYSADDR_SIZE               8
 
+/* Address Object Options */
+#define AO_OPTION_TTL                1
+#define AO_OPTION_MCASTTTL           2
+#define AO_OPTION_MCASTIF            3
+#define AO_OPTION_XSUM               4
+#define AO_OPTION_IPOPTIONS          5
+#define AO_OPTION_ADD_MCAST          6
+#define AO_OPTION_DEL_MCAST          7
+#define AO_OPTION_TOS                8
+#define AO_OPTION_IP_DONTFRAGMENT    9
+#define AO_OPTION_MCASTLOOP         10
+#define AO_OPTION_BROADCAST         11
+#define AO_OPTION_IP_HDRINCL        12
+#define AO_OPTION_RCVALL            13
+#define AO_OPTION_RCVALL_MCAST      14
+#define AO_OPTION_RCVALL_IGMPMCAST  15
+#define AO_OPTION_UNNUMBEREDIF      16
+#define AO_OPTION_IP_UCASTIF        17
+#define AO_OPTION_ABSORB_RTRALERT   18
+#define AO_OPTION_LIMIT_BCASTS      19
+#define AO_OPTION_INDEX_BIND        20
+#define AO_OPTION_INDEX_MCASTIF     21
+#define AO_OPTION_INDEX_ADD_MCAST   22
+#define AO_OPTION_INDEX_DEL_MCAST   23
+#define AO_OPTION_IFLIST            24
+#define AO_OPTION_ADD_IFLIST        25
+#define AO_OPTION_DEL_IFLIST        26
+#define AO_OPTION_IP_PKTINFO        27
+#define AO_OPTION_ADD_MCAST_SRC     28
+#define AO_OPTION_DEL_MCAST_SRC     29
+#define AO_OPTION_MCAST_FILTER      30
+#define AO_OPTION_BLOCK_MCAST_SRC   31
+#define AO_OPTION_UNBLOCK_MCAST_SRC 32
+#define AO_OPTION_UDP_CKSUM_COVER   33
+#define AO_OPTION_WINDOW            34
+#define AO_OPTION_SCALE_CWIN        35
+#define AO_OPTION_RCV_HOPLIMIT      36
+#define AO_OPTION_UNBIND            37
+#define AO_OPTION_PROTECT           38
+
 typedef struct IFEntry
 {
     ULONG if_index;
index 3c715e6..132261e 100644 (file)
@@ -50,7 +50,7 @@ INT WINAPI WSHEnumProtocols(LPINT,LPWSTR,LPVOID,LPDWORD);
 INT WINAPI WSHGetBroadcastSockaddr(PVOID,PSOCKADDR,PINT);
 INT WINAPI WSHGetProviderGuid(LPWSTR,LPGUID);
 INT WINAPI WSHGetSockaddrType(PSOCKADDR,DWORD,PSOCKADDR_INFO);
-INT WINAPI WSHGetSocketInformation(PVOID,SOCKET,HANDLE,HANDLE,INT,INT,PCHAR,INT);
+INT WINAPI WSHGetSocketInformation(PVOID,SOCKET,HANDLE,HANDLE,INT,INT,PCHAR,LPINT);
 INT WINAPI WSHGetWildcardSockaddr(PVOID,PSOCKADDR,PINT);
 DWORD WINAPI WSHGetWinsockMapping(PWINSOCK_MAPPING,DWORD);
 INT WINAPI WSHGetWSAProtocolInfo(LPWSTR,LPWSAPROTOCOL_INFOW*,LPDWORD);
@@ -69,7 +69,7 @@ typedef INT (WINAPI *PWSH_ENUM_PROTOCOLS)(LPINT,LPWSTR,LPVOID,LPDWORD);
 typedef INT (WINAPI *PWSH_GET_BROADCAST_SOCKADDR)(PVOID,PSOCKADDR,PINT);
 typedef INT (WINAPI *PWSH_GET_PROVIDER_GUID)(LPWSTR,LPGUID);
 typedef INT (WINAPI *PWSH_GET_SOCKADDR_TYPE)(PSOCKADDR,DWORD,PSOCKADDR_INFO);
-typedef INT (WINAPI *PWSH_GET_SOCKET_INFORMATION)(PVOID,SOCKET,HANDLE,HANDLE,INT,INT,PCHAR,INT);
+typedef INT (WINAPI *PWSH_GET_SOCKET_INFORMATION)(PVOID,SOCKET,HANDLE,HANDLE,INT,INT,PCHAR,LPINT);
 typedef INT (WINAPI *PWSH_GET_WILDCARD_SOCKEADDR)(PVOID,PSOCKADDR,PINT);
 typedef DWORD (WINAPI *PWSH_GET_WINSOCK_MAPPING)(PWINSOCK_MAPPING,DWORD);
 typedef INT (WINAPI *PWSH_GET_WSAPROTOCOL_INFO)(LPWSTR,LPWSAPROTOCOL_INFOW*,LPDWORD);
index bb60854..53dd633 100644 (file)
@@ -91,8 +91,13 @@ VOID DGDeliverData(
     }
   else
     {
-      /* Give client the IP header too if it is a raw IP file object */
-      DataBuffer = IPPacket->Header;
+      if (AddrFile->HeaderIncl)
+          DataBuffer = IPPacket->Header;
+      else
+      {
+          DataBuffer = IPPacket->Data;
+          DataSize -= IPPacket->HeaderSize;
+      }
     }
 
   if (!IsListEmpty(&AddrFile->ReceiveQueue))
index d8e3f4d..98b2380 100644 (file)
@@ -58,6 +58,9 @@
        <directory name="smlib">
                <xi:include href="smlib/smlib.rbuild" />
        </directory>
+       <directory name="tdilib">
+               <xi:include href="tdilib/tdilib.rbuild" />
+       </directory>
        <directory name="win32ksys">
                <xi:include href="win32ksys/win32ksys.rbuild" />
        </directory>
diff --git a/lib/tdilib/enum.c b/lib/tdilib/enum.c
new file mode 100644 (file)
index 0000000..1ec6c7f
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TDI interface
+ * FILE:        enum.c
+ * PURPOSE:     TDI entity enumeration
+ */
+
+#include "iphlpapi_private.h"
+#include "tdilib.h"
+
+/* A generic thing-getting function which interacts in the right way with
+ * TDI.  This may seem oblique, but I'm using it to reduce code and hopefully
+ * make this thing easier to debug.
+ *
+ * The things returned can be any of:
+ *   TDIEntityID
+ *   TDIObjectID
+ *   IFEntry
+ *   IPSNMPInfo
+ *   IPAddrEntry
+ *   IPInterfaceInfo
+ */
+NTSTATUS tdiGetSetOfThings( HANDLE tcpFile,
+                            DWORD toiClass,
+                            DWORD toiType,
+                            DWORD toiId,
+                            DWORD teiEntity,
+                           DWORD teiInstance,
+                            DWORD fixedPart,
+                            DWORD entrySize,
+                            PVOID *tdiEntitySet,
+                            PDWORD numEntries ) {
+    TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
+    PVOID entitySet = 0;
+    NTSTATUS status = STATUS_SUCCESS;
+    DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES,
+        arraySize = entrySize * MAX_TDI_ENTITIES;
+
+    req.ID.toi_class                = toiClass;
+    req.ID.toi_type                 = toiType;
+    req.ID.toi_id                   = toiId;
+    req.ID.toi_entity.tei_entity    = teiEntity;
+    req.ID.toi_entity.tei_instance  = teiInstance;
+
+    /* There's a subtle problem here...
+     * If an interface is added at this exact instant, (as if by a PCMCIA
+     * card insertion), the array will still not have enough entries after
+     * have allocated it after the first DeviceIoControl call.
+     *
+     * We'll get around this by repeating until the number of interfaces
+     * stabilizes.
+     */
+    do {
+        status = DeviceIoControl( tcpFile,
+                                  IOCTL_TCP_QUERY_INFORMATION_EX,
+                                  &req,
+                                  sizeof(req),
+                                  0,
+                                  0,
+                                  &allocationSizeForEntityArray,
+                                  NULL );
+
+        if(!status)
+        {
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        arraySize = allocationSizeForEntityArray;
+        entitySet = HeapAlloc( GetProcessHeap(), 0, arraySize );
+
+        if( !entitySet ) {
+            status = STATUS_INSUFFICIENT_RESOURCES;
+            return status;
+        }
+
+        status = DeviceIoControl( tcpFile,
+                                  IOCTL_TCP_QUERY_INFORMATION_EX,
+                                  &req,
+                                  sizeof(req),
+                                  entitySet,
+                                  arraySize,
+                                  &allocationSizeForEntityArray,
+                                  NULL );
+
+        /* This is why we have the loop -- we might have added an adapter */
+        if( arraySize == allocationSizeForEntityArray )
+            break;
+
+        HeapFree( GetProcessHeap(), 0, entitySet );
+        entitySet = 0;
+
+        if(!status)
+            return STATUS_UNSUCCESSFUL;
+    } while( TRUE ); /* We break if the array we received was the size we
+                      * expected.  Therefore, we got here because it wasn't */
+
+    *numEntries = (arraySize - fixedPart) / entrySize;
+    *tdiEntitySet = entitySet;
+
+    return STATUS_SUCCESS;
+}
+
+VOID tdiFreeThingSet( PVOID things ) {
+    HeapFree( GetProcessHeap(), 0, things );
+}
+
+NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile,
+                            TDIEntityID **entitySet,
+                            PDWORD numEntities ) {
+    NTSTATUS status = tdiGetSetOfThings( tcpFile,
+                                         INFO_CLASS_GENERIC,
+                                         INFO_TYPE_PROVIDER,
+                                         ENTITY_LIST_ID,
+                                         GENERIC_ENTITY,
+                                        0,
+                                         0,
+                                         sizeof(TDIEntityID),
+                                         (PVOID *)entitySet,
+                                         numEntities );
+
+    return status;
+}
+
diff --git a/lib/tdilib/handle.c b/lib/tdilib/handle.c
new file mode 100644 (file)
index 0000000..39399b6
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TDI interface
+ * FILE:        handle.c
+ * PURPOSE:     TDI transport handle management
+ */
+
+#include "iphlpapi_private.h"
+
+const PWCHAR TcpFileName = L"\\Device\\Tcp";
+
+NTSTATUS openTcpFile(PHANDLE tcpFile)
+{
+    UNICODE_STRING fileName;
+    OBJECT_ATTRIBUTES objectAttributes;
+    IO_STATUS_BLOCK ioStatusBlock;
+    NTSTATUS status;
+
+    RtlInitUnicodeString( &fileName, TcpFileName );
+
+    InitializeObjectAttributes( &objectAttributes,
+                                &fileName,
+                                OBJ_CASE_INSENSITIVE,
+                                NULL,
+                                NULL );
+
+    status = ZwCreateFile( tcpFile,
+                           SYNCHRONIZE | GENERIC_EXECUTE |
+                           GENERIC_READ | GENERIC_WRITE,
+                           &objectAttributes,
+                           &ioStatusBlock,
+                           NULL,
+                           FILE_ATTRIBUTE_NORMAL,
+                           FILE_SHARE_READ | FILE_SHARE_WRITE,
+                           FILE_OPEN_IF,
+                           FILE_SYNCHRONOUS_IO_NONALERT,
+                           0,
+                           0 );
+
+    /* String does not need to be freed: it points to the constant
+     * string we provided */
+
+    if (!NT_SUCCESS(status))
+        *tcpFile = INVALID_HANDLE_VALUE;
+
+    return status;
+}
+
+VOID closeTcpFile( HANDLE h )
+{
+    ASSERT(h != INVALID_HANDLE_VALUE);
+
+    NtClose( h );
+}
diff --git a/lib/tdilib/tdilib.h b/lib/tdilib/tdilib.h
new file mode 100644 (file)
index 0000000..3223138
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TDI interface
+ * FILE:        tdilib.h
+ * PURPOSE:     Shared TDI library header
+ */
+
+#ifndef TDILIB_H
+#define TDILIB_H
+NTSTATUS openTcpFile(PHANDLE tcpFile);
+VOID closeTcpFile(HANDLE tcpFile);
+NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile, TDIEntityID **entitySet,
+                           PDWORD numEntities );
+NTSTATUS tdiGetSetOfThings( HANDLE tcpFile, DWORD toiClass, DWORD toiType,
+                           DWORD toiId, DWORD teiEntity, DWORD teiInstance,
+                           DWORD fixedPart,
+                           DWORD entrySize, PVOID *tdiEntitySet,
+                           PDWORD numEntries );
+VOID tdiFreeThingSet( PVOID things );
+#endif
diff --git a/lib/tdilib/tdilib.rbuild b/lib/tdilib/tdilib.rbuild
new file mode 100644 (file)
index 0000000..6c8cc60
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<module name="tdilib" type="staticlibrary">
+       <include base="iphlpapi">.</include>
+       <include base="tdilib">.</include>
+       <library>ntdll</library>
+       <file>enum.c</file>
+       <file>handle.c</file>
+</module>