From 3f6a56fa3611da3460a359941bfe6fae4bc3835d Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 16 Jan 2010 00:05:15 +0000 Subject: [PATCH] [TDILIB, IPHLPAPI, WSHTCPIP] - 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 --- dll/win32/iphlpapi/ifenum_reactos.c | 195 ----------------- dll/win32/iphlpapi/iphlpapi.rbuild | 2 + dll/win32/iphlpapi/iphlpapi_private.h | 13 +- dll/win32/msafd/misc/dllmain.c | 140 +++++++++++- dll/win32/msafd/misc/stubs.c | 16 -- dll/win32/wshirda/wshirda.c | 2 +- dll/win32/wshtcpip/wshtcpip.c | 217 ++++++++++++++++++- dll/win32/wshtcpip/wshtcpip.h | 19 ++ dll/win32/wshtcpip/wshtcpip.rbuild | 2 + drivers/network/afd/afd/connect.c | 2 +- drivers/network/tcpip/include/titypes.h | 3 + drivers/network/tcpip/tcpip/ainfo.c | 41 +++- drivers/network/tcpip/tcpip/fileobjs.c | 7 +- include/psdk/tcpioctl.h | 40 ++++ include/psdk/wsahelp.h | 4 +- lib/drivers/ip/transport/datagram/datagram.c | 9 +- lib/lib.rbuild | 3 + lib/tdilib/enum.c | 123 +++++++++++ lib/tdilib/handle.c | 54 +++++ lib/tdilib/tdilib.h | 20 ++ lib/tdilib/tdilib.rbuild | 9 + 21 files changed, 670 insertions(+), 251 deletions(-) create mode 100644 lib/tdilib/enum.c create mode 100644 lib/tdilib/handle.c create mode 100644 lib/tdilib/tdilib.h create mode 100644 lib/tdilib/tdilib.rbuild diff --git a/dll/win32/iphlpapi/ifenum_reactos.c b/dll/win32/iphlpapi/ifenum_reactos.c index 55c5c10a845..8eec8a77b1f 100644 --- a/dll/win32/iphlpapi/ifenum_reactos.c +++ b/dll/win32/iphlpapi/ifenum_reactos.c @@ -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; diff --git a/dll/win32/iphlpapi/iphlpapi.rbuild b/dll/win32/iphlpapi/iphlpapi.rbuild index 6582639fe05..3ef209f722d 100644 --- a/dll/win32/iphlpapi/iphlpapi.rbuild +++ b/dll/win32/iphlpapi/iphlpapi.rbuild @@ -3,12 +3,14 @@ . include/reactos/wine include + . wine ntdll kernel32 advapi32 ws2_32 dhcpcsvc + tdilib dhcp_reactos.c ifenum_reactos.c ipstats_reactos.c diff --git a/dll/win32/iphlpapi/iphlpapi_private.h b/dll/win32/iphlpapi/iphlpapi_private.h index 4210198a20c..90efff74da0 100644 --- a/dll/win32/iphlpapi/iphlpapi_private.h +++ b/dll/win32/iphlpapi/iphlpapi_private.h @@ -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, diff --git a/dll/win32/msafd/misc/dllmain.c b/dll/win32/msafd/misc/dllmain.c index 9c10829c70c..d01a97edc56 100644 --- a/dll/win32/msafd/misc/dllmain.c +++ b/dll/win32/msafd/misc/dllmain.c @@ -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 diff --git a/dll/win32/msafd/misc/stubs.c b/dll/win32/msafd/misc/stubs.c index 6de00a6965d..5a9da712616 100644 --- a/dll/win32/msafd/misc/stubs.c +++ b/dll/win32/msafd/misc/stubs.c @@ -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( diff --git a/dll/win32/wshirda/wshirda.c b/dll/win32/wshirda/wshirda.c index 1ee48248a73..eee977e8835 100644 --- a/dll/win32/wshirda/wshirda.c +++ b/dll/win32/wshirda/wshirda.c @@ -91,7 +91,7 @@ WSHGetSocketInformation( IN INT Level, IN INT OptionName, OUT PCHAR OptionValue, - OUT INT OptionLength) + OUT LPINT OptionLength) { UNIMPLEMENTED diff --git a/dll/win32/wshtcpip/wshtcpip.c b/dll/win32/wshtcpip/wshtcpip.c index 91c7fbaee53..c585128adfb 100644 --- a/dll/win32/wshtcpip/wshtcpip.c +++ b/dll/win32/wshtcpip/wshtcpip.c @@ -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; } diff --git a/dll/win32/wshtcpip/wshtcpip.h b/dll/win32/wshtcpip/wshtcpip.h index a9ad8e26bc6..6a3ece000ee 100644 --- a/dll/win32/wshtcpip/wshtcpip.h +++ b/dll/win32/wshtcpip/wshtcpip.h @@ -9,6 +9,10 @@ #define WIN32_NO_STATUS #include +#include +#include +#include +#include #include #define EXPORT WINAPI @@ -17,12 +21,27 @@ #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 */ diff --git a/dll/win32/wshtcpip/wshtcpip.rbuild b/dll/win32/wshtcpip/wshtcpip.rbuild index 84e3cae9a1d..c224d5f6678 100644 --- a/dll/win32/wshtcpip/wshtcpip.rbuild +++ b/dll/win32/wshtcpip/wshtcpip.rbuild @@ -3,9 +3,11 @@ . + . ntdll kernel32 ws2_32 + tdilib wshtcpip.c wshtcpip.rc diff --git a/drivers/network/afd/afd/connect.c b/drivers/network/afd/afd/connect.c index 7ee3abaec57..c49e6518243 100644 --- a/drivers/network/afd/afd/connect.c +++ b/drivers/network/afd/afd/connect.c @@ -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 ); diff --git a/drivers/network/tcpip/include/titypes.h b/drivers/network/tcpip/include/titypes.h index 5a921e4fd10..fb8ec7749d6 100644 --- a/drivers/network/tcpip/include/titypes.h +++ b/drivers/network/tcpip/include/titypes.h @@ -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 */ diff --git a/drivers/network/tcpip/tcpip/ainfo.c b/drivers/network/tcpip/tcpip/ainfo.c index 0c1b11e717f..03172020749 100644 --- a/drivers/network/tcpip/tcpip/ainfo.c +++ b/drivers/network/tcpip/tcpip/ainfo.c @@ -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); diff --git a/drivers/network/tcpip/tcpip/fileobjs.c b/drivers/network/tcpip/tcpip/fileobjs.c index 62ca63c7686..bd7968e5ede 100644 --- a/drivers/network/tcpip/tcpip/fileobjs.c +++ b/drivers/network/tcpip/tcpip/fileobjs.c @@ -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 */ diff --git a/include/psdk/tcpioctl.h b/include/psdk/tcpioctl.h index 033ec11309d..28d0f351773 100644 --- a/include/psdk/tcpioctl.h +++ b/include/psdk/tcpioctl.h @@ -50,6 +50,46 @@ #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; diff --git a/include/psdk/wsahelp.h b/include/psdk/wsahelp.h index 3c715e622a5..132261e0668 100644 --- a/include/psdk/wsahelp.h +++ b/include/psdk/wsahelp.h @@ -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); diff --git a/lib/drivers/ip/transport/datagram/datagram.c b/lib/drivers/ip/transport/datagram/datagram.c index bb608545fa3..53dd6331ea9 100644 --- a/lib/drivers/ip/transport/datagram/datagram.c +++ b/lib/drivers/ip/transport/datagram/datagram.c @@ -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)) diff --git a/lib/lib.rbuild b/lib/lib.rbuild index d8e3f4de44d..98b2380a67a 100644 --- a/lib/lib.rbuild +++ b/lib/lib.rbuild @@ -58,6 +58,9 @@ + + + diff --git a/lib/tdilib/enum.c b/lib/tdilib/enum.c new file mode 100644 index 00000000000..1ec6c7fa1bc --- /dev/null +++ b/lib/tdilib/enum.c @@ -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 index 00000000000..39399b6653a --- /dev/null +++ b/lib/tdilib/handle.c @@ -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 index 00000000000..32231384f69 --- /dev/null +++ b/lib/tdilib/tdilib.h @@ -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 index 00000000000..6c8cc60c99d --- /dev/null +++ b/lib/tdilib/tdilib.rbuild @@ -0,0 +1,9 @@ + + + + . + . + ntdll + enum.c + handle.c +