- Rewrite most of the lower TCP layer code to work with lwIP
[LWIP]
- Write all of the implementation-specific code and headers
[TCPIP]
- Add assertions in the object reference functions
- Remove the completion queue hack

This is still isn't totally finished yet. There are still two main issues that need to be overcome: listen/accept don't work at all and the performance is horrible.
I hope that once I tune some of the options, I can get it to perform reasonably well. If any curious testers want to try this out, be my guest but realize that not
a lot of apps will work yet. Suggestions are welcome! :)

svn path=/branches/tcp-rewrite-branch/; revision=48840
This commit is contained in:
Cameron Gutman 2010-09-21 06:11:24 +00:00
parent fa58fc5f13
commit 459e413725
25 changed files with 2116 additions and 1000 deletions

View file

@ -29,7 +29,6 @@
#include <fileobjs.h>
#include <lock.h>
#include <wait.h>
#include <oskittcp.h>
#include <interface.h>
#include <ports.h>
#include <ipifcons.h>

View file

@ -24,15 +24,6 @@ typedef struct TCPv4_HEADER {
USHORT Urgent; /* Pointer to urgent data */
} TCPv4_HEADER, *PTCPv4_HEADER;
/* TCPv4 header flags */
#define TCP_URG 0x20
#define TCP_ACK 0x10
#define TCP_PSH 0x08
#define TCP_RST 0x04
#define TCP_SYN 0x02
#define TCP_FIN 0x01
#define TCPOPT_END_OF_LIST 0x0
#define TCPOPT_NO_OPERATION 0x1
#define TCPOPT_MAX_SEG_SIZE 0x2
@ -79,6 +70,19 @@ typedef struct _CLIENT_DATA {
/* Delay variance factor */
#define TCP_BETA_RETRANSMISSION_TIMEOUT(x)(((x)*16)/10) /* 1.6 */
#define SEL_CONNECT 1
#define SEL_FIN 2
#define SEL_RST 4
#define SEL_ABRT 8
#define SEL_READ 16
#define SEL_WRITE 32
#define SEL_ACCEPT 64
#define SEL_OOB 128
#define SEL_ERROR 256
#define SEL_FINOUT 512
#define FREAD 0x0001
#define FWRITE 0x0002
/* Datagram/segment send request flags */
@ -93,9 +97,8 @@ extern LONG TCP_IPIdentification;
extern CLIENT_DATA ClientInfo;
/* accept.c */
NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
PCONNECTION_ENDPOINT Connection,
PTDI_REQUEST_KERNEL Request );
NTSTATUS TCPCheckPeerForAccept(PVOID Context,
PTDI_REQUEST_KERNEL Request);
NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog );
BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
PCONNECTION_ENDPOINT Connection );
@ -163,7 +166,7 @@ NTSTATUS TCPSendData(
NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection );
NTSTATUS TCPTranslateError( int OskitError );
NTSTATUS TCPTranslateError( INT8 err );
UINT TCPAllocatePort( UINT HintPort );
@ -181,3 +184,12 @@ NTSTATUS TCPShutdown(
VOID);
BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Connection, PIRP Irp );
VOID
TCPUpdateInterfaceLinkStatus(PIP_INTERFACE IF);
VOID
TCPUpdateInterfaceIPInformation(PIP_INTERFACE IF);
VOID
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status);

View file

@ -135,19 +135,9 @@ struct in_addr
#define s_impno S_un.S_un_b.s_b4
#define s_lh S_un.S_un_b.s_b3
};
struct sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
typedef struct sockaddr_in SOCKADDR_IN;
struct sockaddr
{
u_short sa_family;
char sa_data[14];
};
#define __LWIP_INET_H__
#include "lwip/sockets.h"
/* Sufficient information to manage the entity list */
typedef struct {

View file

@ -13,6 +13,7 @@
*/
#define ReferenceObject(Object) \
{ \
ASSERT(((Object)->RefCount) > 0); \
InterlockedIncrement(&((Object)->RefCount)); \
}
@ -22,6 +23,7 @@
*/
#define DereferenceObject(Object) \
{ \
ASSERT(((Object)->RefCount) > 0); \
if (InterlockedDecrement(&((Object)->RefCount)) == 0) \
(((Object)->Free)(Object)); \
}
@ -33,7 +35,7 @@
{ \
ReferenceObject(Object); \
KeAcquireSpinLock(&((Object)->Lock), Irql); \
memcpy(&(Object)->OldIrql, Irql, sizeof(KIRQL)); \
(Object)->OldIrql = *Irql; \
}
/*
@ -266,10 +268,6 @@ typedef struct _CONNECTION_ENDPOINT {
LIST_ENTRY ListenRequest; /* Queued listen requests */
LIST_ENTRY ReceiveRequest; /* Queued receive requests */
LIST_ENTRY SendRequest; /* Queued send requests */
LIST_ENTRY CompletionQueue;/* Completed requests to finish */
/* Signals */
UINT SignalState; /* Active signals from oskit */
} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT;

View file

@ -3,11 +3,12 @@
<module name="tcpip" type="kernelmodedriver" installbase="system32/drivers" installname="tcpip.sys">
<importlibrary definition="tcpip.spec" />
<include base="tcpip">include</include>
<include base="oskittcp">include</include>
<include base="lwip">src/include</include>
<include base="lwip">src/include/ipv4</include>
<define name="NDIS40" />
<define name="_NTDRIVER_" />
<library>ip</library>
<library>oskittcp</library>
<library>lwip</library>
<library>ndis</library>
<library>pseh</library>
<library>chew</library>

View file

@ -10,6 +10,9 @@
<directory name="oskittcp">
<xi:include href="oskittcp/oskittcp.rbuild" />
</directory>
<directory name="lwip">
<xi:include href="lwip/lwip.rbuild" />
</directory>
<directory name="chew">
<xi:include href="chew/chew.rbuild" />
</directory>

View file

@ -3,7 +3,8 @@
<module name="ip" type="staticlibrary">
<define name="__NTDRIVER__"/>
<include base="tcpip">include</include>
<include base="oskittcp">include</include>
<include base="lwip">src/include</include>
<include base="lwip">src/include/ipv4</include>
<directory name="network">
<if property="ARCH" value="i386">
<directory name="i386">

View file

@ -10,6 +10,9 @@
#include "precomp.h"
#define __LWIP_INET_H__
#include "lwip/netifapi.h"
LIST_ENTRY InterfaceListHead;
KSPIN_LOCK InterfaceListLock;
@ -21,6 +24,12 @@ BOOLEAN IpWorkItemQueued = FALSE;
IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
VOID
TCPRegisterInterface(PIP_INTERFACE IF);
VOID
TCPUnregisterInterface(PIP_INTERFACE IF);
VOID DontFreePacket(
PVOID Object)
/*
@ -162,13 +171,14 @@ PIP_INTERFACE IPCreateInterface(
TcpipInitializeSpinLock(&IF->Lock);
IF->TCPContext = ExAllocatePoolWithTag
( NonPagedPool, sizeof(OSK_IFADDR) + 3 * sizeof( struct sockaddr_in ),
OSKITTCP_CONTEXT_TAG );
IF->TCPContext = ExAllocatePool
( NonPagedPool, sizeof(struct netif));
if (!IF->TCPContext) {
ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
return NULL;
}
TCPRegisterInterface(IF);
#ifdef __NTDRIVER__
InsertTDIInterfaceEntity( IF );
@ -191,8 +201,10 @@ VOID IPDestroyInterface(
#ifdef __NTDRIVER__
RemoveTDIInterfaceEntity( IF );
#endif
TCPUnregisterInterface(IF);
ExFreePoolWithTag(IF->TCPContext, OSKITTCP_CONTEXT_TAG);
ExFreePool(IF->TCPContext);
ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
}
@ -219,6 +231,8 @@ VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
* other computers */
if (IF != Loopback)
ARPTransmit(NULL, NULL, IF);
TCPUpdateInterfaceIPInformation(IF);
}
BOOLEAN IPRegisterInterface(

View file

@ -54,46 +54,9 @@ static VOID DisplayIPHeader(
((IPHeader->DstAddr >> 16) & 0xFF), ((IPHeader->DstAddr >> 24) & 0xFF));
}
static VOID DisplayTCPHeader(
PCHAR Header,
UINT Length)
{
/* FIXME: IPv4 only */
PIPv4_HEADER IPHeader = (PIPv4_HEADER)Header;
PTCPv4_HEADER TCPHeader;
if (IPHeader->Protocol != IPPROTO_TCP) {
DbgPrint("This is not a TCP datagram. Protocol is %d\n", IPHeader->Protocol);
return;
}
TCPHeader = (PTCPv4_HEADER)((PCHAR)IPHeader + (IPHeader->VerIHL & 0x0F) * 4);
DbgPrint("TCP header:\n");
DbgPrint(" SourcePort: %d\n", WN2H(TCPHeader->SourcePort));
DbgPrint(" DestinationPort: %d\n", WN2H(TCPHeader->DestinationPort));
DbgPrint(" SequenceNumber: 0x%x\n", DN2H(TCPHeader->SequenceNumber));
DbgPrint(" AckNumber: 0x%x\n", DN2H(TCPHeader->AckNumber));
DbgPrint(" DataOffset: 0x%x (0x%x) 32-bit words\n", TCPHeader->DataOffset, TCPHeader->DataOffset >> 4);
DbgPrint(" Flags: 0x%x (0x%x)\n", TCPHeader->Flags, TCPHeader->Flags & 0x3F);
if ((TCPHeader->Flags & TCP_URG) > 0) DbgPrint(" TCP_URG - Urgent Pointer field significant\n");
if ((TCPHeader->Flags & TCP_ACK) > 0) DbgPrint(" TCP_ACK - Acknowledgement field significant\n");
if ((TCPHeader->Flags & TCP_PSH) > 0) DbgPrint(" TCP_PSH - Push Function\n");
if ((TCPHeader->Flags & TCP_RST) > 0) DbgPrint(" TCP_RST - Reset the connection\n");
if ((TCPHeader->Flags & TCP_SYN) > 0) DbgPrint(" TCP_SYN - Synchronize sequence numbers\n");
if ((TCPHeader->Flags & TCP_FIN) > 0) DbgPrint(" TCP_FIN - No more data from sender\n");
DbgPrint(" Window: 0x%x\n", WN2H(TCPHeader->Window));
DbgPrint(" Checksum: 0x%x\n", WN2H(TCPHeader->Checksum));
DbgPrint(" Urgent: 0x%x\n", WN2H(TCPHeader->Urgent));
}
VOID DisplayTCPPacket(
PIP_PACKET IPPacket)
{
UINT Length;
PCHAR Buffer;
if ((DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_PBUFFER | DPFLTR_MASK) != TRUE) ||
(DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_TCP | DPFLTR_MASK) != TRUE)) {
return;
@ -112,20 +75,6 @@ VOID DisplayTCPPacket(
TI_DbgPrint(MIN_TRACE, ("TotalSize (%d).\n", IPPacket->TotalSize));
TI_DbgPrint(MIN_TRACE, ("ContigSize (%d).\n", IPPacket->ContigSize));
TI_DbgPrint(MIN_TRACE, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket));
if (IPPacket->NdisPacket) {
NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &Length);
Buffer = ExAllocatePool(NonPagedPool, Length);
if (Buffer) {
Length = CopyPacketToBuffer(Buffer, IPPacket->NdisPacket, 0, Length);
DisplayTCPHeader(Buffer, Length);
ExFreePool(Buffer);
}
} else {
Buffer = IPPacket->Header;
Length = IPPacket->ContigSize;
DisplayTCPHeader(Buffer, Length);
}
}
#endif

View file

@ -10,55 +10,32 @@
#include "precomp.h"
/* Listener->Lock MUST be acquired */
NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
PCONNECTION_ENDPOINT Connection,
PTDI_REQUEST_KERNEL Request ) {
#include "rosip.h"
NTSTATUS TCPCheckPeerForAccept(PVOID Context,
PTDI_REQUEST_KERNEL Request) {
struct tcp_pcb *newpcb = Context;
NTSTATUS Status;
SOCKADDR_IN OutAddr;
OSK_UINT OutAddrLen;
PTA_IP_ADDRESS RequestAddressReturn;
PTDI_CONNECTION_INFORMATION WhoIsConnecting;
PTA_IP_ADDRESS RemoteAddress;
struct ip_addr ipaddr;
if (Request->RequestFlags & TDI_QUERY_ACCEPT)
DbgPrint("TDI_QUERY_ACCEPT NOT SUPPORTED!!!\n");
/* Unpack TDI info -- We need the return connection information
* struct to return the address so it can be filtered if needed
* by WSAAccept -- The returned address will be passed on to
* userland after we complete this irp */
WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)
Request->ReturnConnectionInformation;
Status = TCPTranslateError
( OskitTCPAccept( Listener->SocketContext,
&Connection->SocketContext,
Connection,
&OutAddr,
sizeof(OutAddr),
&OutAddrLen,
Request->RequestFlags & TDI_QUERY_ACCEPT ? 0 : 1 ) );
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
if( NT_SUCCESS(Status) && Status != STATUS_PENDING ) {
RequestAddressReturn = WhoIsConnecting->RemoteAddress;
TI_DbgPrint(DEBUG_TCP,("Copying address to %x (Who %x)\n",
RequestAddressReturn, WhoIsConnecting));
RequestAddressReturn->TAAddressCount = 1;
RequestAddressReturn->Address[0].AddressLength = OutAddrLen;
/* BSD uses the first byte of the sockaddr struct as a length.
* Since windows doesn't do that we strip it */
RequestAddressReturn->Address[0].AddressType =
(OutAddr.sin_family >> 8) & 0xff;
RtlCopyMemory( &RequestAddressReturn->Address[0].Address,
((PCHAR)&OutAddr) + sizeof(USHORT),
sizeof(RequestAddressReturn->Address[0].Address[0]) );
TI_DbgPrint(DEBUG_TCP,("Done copying\n"));
}
WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)Request->ReturnConnectionInformation;
RemoteAddress = (PTA_IP_ADDRESS)WhoIsConnecting->RemoteAddress;
RemoteAddress->TAAddressCount = 1;
RemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
RemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
Status = TCPTranslateError(LibTCPGetPeerName(newpcb,
&ipaddr,
&RemoteAddress->Address[0].Address[0].sin_port));
RemoteAddress->Address[0].Address[0].in_addr = ipaddr.addr;
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
return Status;
@ -68,7 +45,7 @@ NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
* lifetime as the address file */
NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) {
NTSTATUS Status = STATUS_SUCCESS;
SOCKADDR_IN AddressToBind;
struct ip_addr AddressToBind;
KIRQL OldIrql;
ASSERT(Connection);
@ -80,21 +57,19 @@ NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) {
TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
Connection->SocketContext));
AddressToBind.addr = Connection->AddressFile->Address.Address.IPv4Address;
AddressToBind.sin_family = AF_INET;
memcpy( &AddressToBind.sin_addr,
&Connection->AddressFile->Address.Address.IPv4Address,
sizeof(AddressToBind.sin_addr) );
AddressToBind.sin_port = Connection->AddressFile->Port;
TI_DbgPrint(DEBUG_TCP,("AddressToBind - %x:%x\n", AddressToBind.sin_addr, AddressToBind.sin_port));
Status = TCPTranslateError( OskitTCPBind( Connection->SocketContext,
&AddressToBind,
sizeof(AddressToBind) ) );
Status = TCPTranslateError(LibTCPBind(Connection->SocketContext,
&AddressToBind,
Connection->AddressFile->Port));
if (NT_SUCCESS(Status))
Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext, Backlog ) );
{
Connection->SocketContext = LibTCPListen(Connection->SocketContext, Backlog);
if (!Connection->SocketContext)
Status = STATUS_UNSUCCESSFUL;
}
UnlockObject(Connection, OldIrql);
@ -145,22 +120,17 @@ NTSTATUS TCPAccept ( PTDI_REQUEST Request,
LockObject(Listener, &OldIrql);
Status = TCPServiceListeningSocket( Listener, Connection,
(PTDI_REQUEST_KERNEL)Request );
if( Status == STATUS_PENDING ) {
Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket),
TDI_BUCKET_TAG );
if( Bucket ) {
ReferenceObject(Connection);
Bucket->AssociatedEndpoint = Connection;
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
InsertTailList( &Listener->ListenRequest, &Bucket->Entry );
} else
Status = STATUS_NO_MEMORY;
}
Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket),
TDI_BUCKET_TAG );
if( Bucket ) {
Bucket->AssociatedEndpoint = Connection;
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
InsertTailList( &Listener->ListenRequest, &Bucket->Entry );
Status = STATUS_PENDING;
} else
Status = STATUS_NO_MEMORY;
UnlockObject(Listener, OldIrql);

View file

@ -2,248 +2,327 @@
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: transport/tcp/event.c
* PURPOSE: Transmission Control Protocol -- Events from oskittcp
* PROGRAMMERS: Art Yerkes
* REVISIONS:
* CSH 01/08-2000 Created
* PURPOSE: Transmission Control Protocol
* PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
*/
#include "precomp.h"
int TCPSocketState(void *ClientData,
void *WhichSocket,
void *WhichConnection,
OSK_UINT NewState ) {
PCONNECTION_ENDPOINT Connection = WhichConnection;
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "lwip/api.h"
TI_DbgPrint(DEBUG_TCP,("Connection: %x Flags: %c%c%c%c%c\n",
Connection,
NewState & SEL_CONNECT ? 'C' : 'c',
NewState & SEL_READ ? 'R' : 'r',
NewState & SEL_FIN ? 'F' : 'f',
NewState & SEL_ACCEPT ? 'A' : 'a',
NewState & SEL_WRITE ? 'W' : 'w'));
#include "rosip.h"
/* If this socket is missing its socket context, that means that it
* has been created as a new connection in sonewconn but not accepted
* yet. We can safely ignore event notifications on these sockets.
* Once they are accepted, they will get a socket context and we will
* be able to process them.
*/
if (!Connection)
return 0;
TI_DbgPrint(DEBUG_TCP,("Called: NewState %x (Conn %x) (Change %x)\n",
NewState, Connection,
Connection->SignalState ^ NewState,
NewState));
Connection->SignalState = NewState;
HandleSignalledConnection(Connection);
return 0;
}
void TCPPacketSendComplete( PVOID Context,
PNDIS_PACKET NdisPacket,
NDIS_STATUS NdisStatus ) {
TI_DbgPrint(DEBUG_TCP,("called %x\n", NdisPacket));
FreeNdisPacket(NdisPacket);
TI_DbgPrint(DEBUG_TCP,("done\n"));
}
#define STRINGIFY(x) #x
int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) {
NDIS_STATUS NdisStatus;
PNEIGHBOR_CACHE_ENTRY NCE;
IP_PACKET Packet = { 0 };
IP_ADDRESS RemoteAddress, LocalAddress;
PIPv4_HEADER Header;
if( *data == 0x45 ) { /* IPv4 */
Header = (PIPv4_HEADER)data;
LocalAddress.Type = IP_ADDRESS_V4;
LocalAddress.Address.IPv4Address = Header->SrcAddr;
RemoteAddress.Type = IP_ADDRESS_V4;
RemoteAddress.Address.IPv4Address = Header->DstAddr;
} else {
TI_DbgPrint(MIN_TRACE,("Outgoing packet is not IPv4\n"));
OskitDumpBuffer( data, len );
return OSK_EINVAL;
}
if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
TI_DbgPrint(MIN_TRACE,("Unable to get route to %s\n", A2S(&RemoteAddress)));
return OSK_EADDRNOTAVAIL;
}
NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL, len );
if (NdisStatus != NDIS_STATUS_SUCCESS) {
TI_DbgPrint(DEBUG_TCP, ("Error from NDIS: %08x\n", NdisStatus));
return OSK_ENOBUFS;
}
GetDataPtr( Packet.NdisPacket, 0,
(PCHAR *)&Packet.Header, &Packet.ContigSize );
RtlCopyMemory( Packet.Header, data, len );
Packet.HeaderSize = sizeof(IPv4_HEADER);
Packet.TotalSize = len;
Packet.SrcAddr = LocalAddress;
Packet.DstAddr = RemoteAddress;
if (!NT_SUCCESS(IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL )))
{
FreeNdisPacket(Packet.NdisPacket);
return OSK_EINVAL;
}
return 0;
}
/* Memory management routines
*
* By far the most requests for memory are either for 128 or 2049 byte blocks,
* so we want to satisfy those from lookaside lists. Unfortunately, the
* TCPFree() function doesn't pass the size of the block to be freed, so we
* need to keep track of it ourselves. We do it by prepending each block with
* 4 bytes, indicating if this is a 'L'arge (2049), 'S'mall (128) or 'O'ther
* block.
*/
/* Set to some non-zero value to get a profile of memory allocation sizes */
#define MEM_PROFILE 0
#define SMALL_SIZE 128
#define LARGE_SIZE 2049
#define SIGNATURE_LARGE 'LLLL'
#define SIGNATURE_SMALL 'SSSS'
#define SIGNATURE_OTHER 'OOOO'
static NPAGED_LOOKASIDE_LIST LargeLookasideList;
static NPAGED_LOOKASIDE_LIST SmallLookasideList;
NTSTATUS
TCPMemStartup( void )
VOID
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status)
{
ExInitializeNPagedLookasideList( &LargeLookasideList,
NULL,
NULL,
0,
LARGE_SIZE + sizeof( ULONG ),
OSK_LARGE_TAG,
0 );
ExInitializeNPagedLookasideList( &SmallLookasideList,
NULL,
NULL,
0,
SMALL_SIZE + sizeof( ULONG ),
OSK_SMALL_TAG,
0 );
return STATUS_SUCCESS;
}
void *TCPMalloc( void *ClientData,
OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
void *v;
ULONG Signature;
#if 0 != MEM_PROFILE
static OSK_UINT *Sizes = NULL, *Counts = NULL, ArrayAllocated = 0;
static OSK_UINT ArrayUsed = 0, AllocationCount = 0;
OSK_UINT i, NewSize, *NewArray;
int Found;
Found = 0;
for ( i = 0; i < ArrayUsed && ! Found; i++ ) {
Found = ( Sizes[i] == Bytes );
if ( Found ) {
Counts[i]++;
}
}
if ( ! Found ) {
if ( ArrayAllocated <= ArrayUsed ) {
NewSize = ( 0 == ArrayAllocated ? 16 : 2 * ArrayAllocated );
NewArray = exAllocatePool( NonPagedPool, 2 * NewSize * sizeof( OSK_UINT ) );
if ( NULL != NewArray ) {
if ( 0 != ArrayAllocated ) {
memcpy( NewArray, Sizes,
ArrayAllocated * sizeof( OSK_UINT ) );
exFreePool( Sizes );
memcpy( NewArray + NewSize, Counts,
ArrayAllocated * sizeof( OSK_UINT ) );
exFreePool( Counts );
}
Sizes = NewArray;
Counts = NewArray + NewSize;
ArrayAllocated = NewSize;
} else if ( 0 != ArrayAllocated ) {
exFreePool( Sizes );
exFreePool( Counts );
ArrayAllocated = 0;
}
}
if ( ArrayUsed < ArrayAllocated ) {
Sizes[ArrayUsed] = Bytes;
Counts[ArrayUsed] = 1;
ArrayUsed++;
}
}
if ( 0 == (++AllocationCount % MEM_PROFILE) ) {
TI_DbgPrint(DEBUG_TCP, ("Memory allocation size profile:\n"));
for ( i = 0; i < ArrayUsed; i++ ) {
PTCP_COMPLETION_ROUTINE Complete;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
DbgPrint("Flushing recv/all with status: 0x%x\n", Status);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock))) {
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
TI_DbgPrint(DEBUG_TCP,
("Size %4u Count %5u\n", Sizes[i], Counts[i]));
("Completing Receive request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = Status;
Bucket->Information = 0;
Complete = Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
TI_DbgPrint(DEBUG_TCP, ("End of memory allocation size profile\n"));
if (Status == STATUS_SUCCESS) Status = STATUS_FILE_CLOSED;
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock))) {
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
Bucket->Information = 0;
Complete = Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
#endif /* MEM_PROFILE */
if ( SMALL_SIZE == Bytes ) {
v = ExAllocateFromNPagedLookasideList( &SmallLookasideList );
Signature = SIGNATURE_SMALL;
} else if ( LARGE_SIZE == Bytes ) {
v = ExAllocateFromNPagedLookasideList( &LargeLookasideList );
Signature = SIGNATURE_LARGE;
} else {
v = ExAllocatePoolWithTag( NonPagedPool, Bytes + sizeof(ULONG),
OSK_OTHER_TAG );
Signature = SIGNATURE_OTHER;
while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock))) {
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
TI_DbgPrint(DEBUG_TCP,
("Completing Send request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = Status;
Bucket->Information = 0;
Complete = Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
if( v ) {
*((ULONG *) v) = Signature;
v = (void *)((char *) v + sizeof(ULONG));
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock))) {
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
Bucket->Information = 0;
Complete = Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
return v;
DereferenceObject(Connection);
}
void TCPFree( void *ClientData,
void *data, OSK_PCHAR File, OSK_UINT Line ) {
ULONG Signature;
data = (void *)((char *) data - sizeof(ULONG));
Signature = *((ULONG *) data);
if ( SIGNATURE_SMALL == Signature ) {
ExFreeToNPagedLookasideList( &SmallLookasideList, data );
} else if ( SIGNATURE_LARGE == Signature ) {
ExFreeToNPagedLookasideList( &LargeLookasideList, data );
} else if ( SIGNATURE_OTHER == Signature ) {
ExFreePoolWithTag( data, OSK_OTHER_TAG );
} else {
ASSERT( FALSE );
}
}
void
TCPMemShutdown( void )
VOID
TCPFinEventHandler(void *arg, err_t err)
{
ExDeleteNPagedLookasideList( &SmallLookasideList );
ExDeleteNPagedLookasideList( &LargeLookasideList );
PCONNECTION_ENDPOINT Connection = arg;
FlushAllQueues(Connection, TCPTranslateError(err));
/* We're already closed so we don't want to call lwip_close */
Connection->SocketContext = NULL;
}
VOID
TCPAcceptEventHandler(void *arg, struct tcp_pcb *newpcb)
{
PCONNECTION_ENDPOINT Connection = arg;
PTCP_COMPLETION_ROUTINE Complete;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
NTSTATUS Status;
KIRQL OldIrql;
DbgPrint("TCPAcceptEventHandler\n");
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock))) {
PIO_STACK_LOCATION IrpSp;
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
Status = TCPCheckPeerForAccept(newpcb,
(PTDI_REQUEST_KERNEL)&IrpSp->Parameters);
TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
Bucket->Status = Status;
Bucket->Information = 0;
DbgPrint("Associated with: 0x%x\n", Bucket->AssociatedEndpoint->SocketContext);
DbgPrint("Completing accept event %x\n", Status);
Complete = Bucket->Request.RequestNotifyObject;
if (Status == STATUS_SUCCESS)
{
LockObject(Bucket->AssociatedEndpoint, &OldIrql);
Bucket->AssociatedEndpoint->SocketContext = newpcb;
LibTCPAccept(newpcb, Bucket->AssociatedEndpoint);
UnlockObject(Bucket->AssociatedEndpoint, OldIrql);
}
DbgPrint("Done!\n");
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
DereferenceObject(Connection);
}
VOID
TCPSendEventHandler(void *arg, u16_t space)
{
PCONNECTION_ENDPOINT Connection = arg;
PTCP_COMPLETION_ROUTINE Complete;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
NTSTATUS Status;
PMDL Mdl;
DbgPrint("TCPSendEventHandler\n");
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock))) {
UINT SendLen = 0;
PVOID SendBuffer = 0;
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
Mdl = Irp->MdlAddress;
TI_DbgPrint(DEBUG_TCP,
("Getting the user buffer from %x\n", Mdl));
NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
TI_DbgPrint(DEBUG_TCP,
("Writing %d bytes to %x\n", SendLen, SendBuffer));
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
TI_DbgPrint
(DEBUG_TCP,
("Connection->SocketContext: %x\n",
Connection->SocketContext));
Status = TCPTranslateError(LibTCPSend(Connection->SocketContext,
SendBuffer,
SendLen));
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", SendLen));
if( Status == STATUS_PENDING ) {
ExInterlockedInsertHeadList(&Connection->SendRequest,
&Bucket->Entry,
&Connection->Lock);
break;
} else {
TI_DbgPrint(DEBUG_TCP,
("Completing Send request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = Status;
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? SendLen : 0;
DbgPrint("Completing send req %x\n", Status);
Complete = Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
}
DereferenceObject(Connection);
}
u32_t
TCPRecvEventHandler(void *arg, struct pbuf *p)
{
PCONNECTION_ENDPOINT Connection = arg;
PTCP_COMPLETION_ROUTINE Complete;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
PMDL Mdl;
UINT Received = 0;
UINT RecvLen;
PUCHAR RecvBuffer;
ASSERT(p);
ReferenceObject(Connection);
DbgPrint("TCPRecvEventHandler\n");
if ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock))) {
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
Mdl = Irp->MdlAddress;
TI_DbgPrint(DEBUG_TCP,
("Getting the user buffer from %x\n", Mdl));
NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
TI_DbgPrint(DEBUG_TCP,
("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
TI_DbgPrint
(DEBUG_TCP,
("Connection->SocketContext: %x\n",
Connection->SocketContext));
TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
RecvLen = MIN(p->tot_len, RecvLen);
for (Received = 0; Received < RecvLen; Received += p->len, p = p->next)
{
DbgPrint("0x%x: Copying %d bytes to 0x%x from 0x%x\n", p, p->len, ((PUCHAR)RecvBuffer) + Received, p->payload);
RtlCopyMemory(RecvBuffer + Received, p->payload, p->len);
}
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
Bucket->Status = STATUS_SUCCESS;
Bucket->Information = Received;
Complete = Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
DereferenceObject(Connection);
return Received;
}
VOID
TCPConnectEventHandler(void *arg, err_t err)
{
PCONNECTION_ENDPOINT Connection = arg;
PTCP_COMPLETION_ROUTINE Complete;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
DbgPrint("TCPConnectEventHandler\n");
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock))) {
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = TCPTranslateError(err);
Bucket->Information = 0;
DbgPrint("Completing connection request! (0x%x)\n", err);
Complete = Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
DereferenceObject(Connection);
}

View file

@ -1,117 +1,170 @@
/*
* Copyright (c) 1997-1998 University of Utah and the Flux Group.
* All rights reserved.
*
* This file is part of the Flux OSKit. The OSKit is free software, also known
* as "open source;" you can redistribute it and/or modify it under the terms
* of the GNU General Public License (GPL), version 2, as published by the Free
* Software Foundation (FSF). To explore alternate licensing terms, contact
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
*
* The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
* received a copy of the GPL along with the OSKit; see the file COPYING. If
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
*/
#include "precomp.h"
int if_index = 0;
struct ifaddr **ifnet_addrs;
#include "lwip/pbuf.h"
#include "lwip/netifapi.h"
#include "lwip/ip.h"
#include "lwip/api.h"
#include "lwip/tcpip.h"
int ifqmaxlen = OSK_IFQ_MAXLEN;
struct ifnet *ifnet;
/*
* Network interface utility routines.
*
* Routines with ifa_ifwith* names take sockaddr *'s as
* parameters.
*/
POSK_IFADDR TCPGetInterfaceData( PIP_INTERFACE IF ) {
NTSTATUS Status;
POSK_IFADDR ifaddr = IF->TCPContext;
struct sockaddr_in *addr_in;
struct sockaddr_in *dstaddr_in;
struct sockaddr_in *netmask_in;
ASSERT(ifaddr);
RtlZeroMemory(ifaddr, sizeof(OSK_IFADDR) + 3 * sizeof( struct sockaddr_in ));
addr_in = (struct sockaddr_in *)&ifaddr[1];
dstaddr_in = (struct sockaddr_in *)&addr_in[1];
netmask_in = (struct sockaddr_in *)&dstaddr_in[1];
TI_DbgPrint(DEBUG_TCPIF,("Called\n"));
ifaddr->ifa_addr = (struct sockaddr *)addr_in;
Status = GetInterfaceIPv4Address( IF,
ADE_UNICAST,
(PULONG)&addr_in->sin_addr.s_addr );
ASSERT(NT_SUCCESS(Status));
ifaddr->ifa_dstaddr = (struct sockaddr *)dstaddr_in;
Status = GetInterfaceIPv4Address(IF,
ADE_POINTOPOINT,
(PULONG)&dstaddr_in->sin_addr.s_addr );
ASSERT(NT_SUCCESS(Status));
ifaddr->ifa_netmask = (struct sockaddr *)netmask_in;
Status = GetInterfaceIPv4Address(IF,
ADE_ADDRMASK,
(PULONG)&netmask_in->sin_addr.s_addr );
ASSERT(NT_SUCCESS(Status));
TI_DbgPrint(DEBUG_TCPIF,("interface %x : addr %x\n",
IF, addr_in->sin_addr.s_addr));
ifaddr->ifa_flags = 0;
ifaddr->ifa_refcnt = 0; /* Anachronistic */
ifaddr->ifa_metric = 1; /* We can get it like in ninfo.c, if we want */
ifaddr->ifa_mtu = IF->MTU;
TI_DbgPrint(DEBUG_TCPIF,("Leaving\n"));
return ifaddr;
void TCPPacketSendComplete(PVOID Context, PNDIS_PACKET NdisPacket, NDIS_STATUS NdisStatus)
{
FreeNdisPacket(NdisPacket);
}
POSK_IFADDR TCPFindInterface( void *ClientData,
OSK_UINT AddrType,
OSK_UINT FindType,
OSK_SOCKADDR *ReqAddr,
OSK_IFADDR *Interface ) {
err_t
TCPSendDataCallback(struct netif *netif, struct pbuf *p, struct ip_addr *dest)
{
NDIS_STATUS NdisStatus;
PNEIGHBOR_CACHE_ENTRY NCE;
IP_ADDRESS Destination;
struct sockaddr_in *addr_in = (struct sockaddr_in *)ReqAddr;
POSK_IFADDR InterfaceData;
TI_DbgPrint(DEBUG_TCPIF,("called for type %d\n", FindType));
if( !ReqAddr ) {
TI_DbgPrint(DEBUG_TCPIF,("no addr or no ifaddr (%x)\n", ReqAddr));
return NULL;
IP_PACKET Packet = { 0 };
IP_ADDRESS RemoteAddress, LocalAddress;
PIPv4_HEADER Header;
UINT i;
struct pbuf *p1;
/* The caller frees the pbuf struct */
DbgPrint("Sending data out on %c%c\n", netif->name[0], netif->name[1]);
if (((*(u8_t*)p->payload) & 0xF0) == 0x40)
{
Header = p->payload;
LocalAddress.Type = IP_ADDRESS_V4;
LocalAddress.Address.IPv4Address = Header->SrcAddr;
RemoteAddress.Type = IP_ADDRESS_V4;
RemoteAddress.Address.IPv4Address = Header->DstAddr;
}
else
{
return EINVAL;
}
Destination.Type = IP_ADDRESS_V4;
Destination.Address.IPv4Address = addr_in->sin_addr.s_addr;
TI_DbgPrint(DEBUG_TCPIF,("Address is %x\n", addr_in->sin_addr.s_addr));
NCE = RouteGetRouteToDestination(&Destination);
if (!NCE) return NULL;
InterfaceData = TCPGetInterfaceData(NCE->Interface);
addr_in = (struct sockaddr_in *)
InterfaceData->ifa_addr;
TI_DbgPrint(DEBUG_TCPIF,("returning addr %x\n", addr_in->sin_addr.s_addr));
return InterfaceData;
if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
{
return EINVAL;
}
NdisStatus = AllocatePacketWithBuffer(&Packet.NdisPacket, NULL, p->tot_len);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
return ENOBUFS;
}
GetDataPtr(Packet.NdisPacket, 0, (PCHAR*)&Packet.Header, &Packet.ContigSize);
for (i = 0, p1 = p; i < p->tot_len; i += p1->len, p1 = p1->next)
{
ASSERT(p1);
RtlCopyMemory(((PUCHAR)Packet.Header) + i, p1->payload, p1->len);
}
Packet.HeaderSize = sizeof(IPv4_HEADER);
Packet.TotalSize = p->tot_len;
Packet.SrcAddr = LocalAddress;
Packet.DstAddr = RemoteAddress;
if (!NT_SUCCESS(IPSendDatagram(&Packet, NCE, TCPPacketSendComplete, NULL)))
{
FreeNdisPacket(Packet.NdisPacket);
return EINVAL;
}
return 0;
}
VOID
TCPUpdateInterfaceLinkStatus(PIP_INTERFACE IF)
{
#if 0
ULONG OperationalStatus;
GetInterfaceConnectionStatus(IF, &OperationalStatus);
if (OperationalStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
netif_set_link_up(IF->TCPContext);
else
netif_set_link_down(IF->TCPContext);
#endif
}
err_t
TCPInterfaceInit(struct netif *netif)
{
PIP_INTERFACE IF = netif->state;
netif->hwaddr_len = IF->AddressLength;
RtlCopyMemory(netif->hwaddr, IF->Address, netif->hwaddr_len);
netif->output = TCPSendDataCallback;
netif->mtu = IF->MTU;
netif->name[0] = 'e';
netif->name[1] = 'n';
netif->flags |= NETIF_FLAG_BROADCAST;
TCPUpdateInterfaceLinkStatus(IF);
TCPUpdateInterfaceIPInformation(IF);
return 0;
}
VOID
TCPRegisterInterface(PIP_INTERFACE IF)
{
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;
gw.addr = 0;
ipaddr.addr = 0;
netmask.addr = 0;
IF->TCPContext = netif_add(IF->TCPContext,
&ipaddr,
&netmask,
&gw,
IF,
TCPInterfaceInit,
tcpip_input);
}
VOID
TCPUnregisterInterface(PIP_INTERFACE IF)
{
netif_remove(IF->TCPContext);
}
VOID
TCPUpdateInterfaceIPInformation(PIP_INTERFACE IF)
{
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;
gw.addr = 0;
GetInterfaceIPv4Address(IF,
ADE_UNICAST,
(PULONG)&ipaddr.addr);
GetInterfaceIPv4Address(IF,
ADE_ADDRMASK,
(PULONG)&netmask.addr);
netif_set_addr(IF->TCPContext, &ipaddr, &netmask, &gw);
if (ipaddr.addr != 0)
{
netif_set_up(IF->TCPContext);
netif_set_default(IF->TCPContext);
}
else
{
netif_set_down(IF->TCPContext);
}
}

View file

@ -14,237 +14,22 @@
LONG TCP_IPIdentification = 0;
static BOOLEAN TCPInitialized = FALSE;
static NPAGED_LOOKASIDE_LIST TCPSegmentList;
PORT_SET TCPPorts;
CLIENT_DATA ClientInfo;
VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
NTSTATUS Status;
PIRP Irp;
PMDL Mdl;
KIRQL OldIrql;
PTCP_COMPLETION_ROUTINE Complete;
#include "lwip/pbuf.h"
#include "lwip/ip.h"
#include "lwip/init.h"
#include "lwip/arch.h"
if (ClientInfo.Unlocked)
LockObjectAtDpcLevel(Connection);
TI_DbgPrint(MID_TRACE,("Handling signalled state on %x (%x)\n",
Connection, Connection->SocketContext));
/* Things that can happen when we try the initial connection */
if( Connection->SignalState & (SEL_CONNECT | SEL_FIN) ) {
while (!IsListEmpty(&Connection->ConnectRequest)) {
Entry = RemoveHeadList( &Connection->ConnectRequest );
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = (Connection->SignalState & SEL_CONNECT) ? STATUS_SUCCESS : STATUS_CANCELLED;
Bucket->Information = 0;
InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
}
}
if( Connection->SignalState & (SEL_ACCEPT | SEL_FIN) ) {
/* Handle readable on a listening socket --
* TODO: Implement filtering
*/
TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n",
Connection,
IsListEmpty(&Connection->ListenRequest) ?
"empty" : "nonempty"));
while (!IsListEmpty(&Connection->ListenRequest)) {
PIO_STACK_LOCATION IrpSp;
Entry = RemoveHeadList( &Connection->ListenRequest );
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
Status = TCPServiceListeningSocket
( Connection->AddressFile->Listener,
Bucket->AssociatedEndpoint,
(PTDI_REQUEST_KERNEL)&IrpSp->Parameters );
TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
InsertHeadList( &Connection->ListenRequest, &Bucket->Entry );
break;
} else {
Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
Bucket->Information = 0;
DereferenceObject(Bucket->AssociatedEndpoint);
InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
}
}
}
/* Things that happen after we're connected */
if( Connection->SignalState & (SEL_READ | SEL_FIN) ) {
TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n",
IsListEmpty(&Connection->ReceiveRequest) ?
"empty" : "nonempty"));
while (!IsListEmpty(&Connection->ReceiveRequest)) {
OSK_UINT RecvLen = 0, Received = 0;
PVOID RecvBuffer = 0;
Entry = RemoveHeadList( &Connection->ReceiveRequest );
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
Mdl = Irp->MdlAddress;
TI_DbgPrint(DEBUG_TCP,
("Getting the user buffer from %x\n", Mdl));
NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
TI_DbgPrint(DEBUG_TCP,
("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
TI_DbgPrint
(DEBUG_TCP,
("Connection->SocketContext: %x\n",
Connection->SocketContext));
TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
Status = TCPTranslateError
( OskitTCPRecv( Connection->SocketContext,
RecvBuffer,
RecvLen,
&Received,
0 ) );
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry );
break;
} else {
TI_DbgPrint(DEBUG_TCP,
("Completing Receive request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Received : 0;
InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
}
}
}
if( Connection->SignalState & (SEL_WRITE | SEL_FIN) ) {
TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n",
IsListEmpty(&Connection->SendRequest) ?
"empty" : "nonempty"));
while (!IsListEmpty(&Connection->SendRequest)) {
OSK_UINT SendLen = 0, Sent = 0;
PVOID SendBuffer = 0;
Entry = RemoveHeadList( &Connection->SendRequest );
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
Mdl = Irp->MdlAddress;
TI_DbgPrint(DEBUG_TCP,
("Getting the user buffer from %x\n", Mdl));
NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
TI_DbgPrint(DEBUG_TCP,
("Writing %d bytes to %x\n", SendLen, SendBuffer));
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
TI_DbgPrint
(DEBUG_TCP,
("Connection->SocketContext: %x\n",
Connection->SocketContext));
Status = TCPTranslateError
( OskitTCPSend( Connection->SocketContext,
SendBuffer,
SendLen,
&Sent,
0 ) );
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent));
if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
InsertHeadList( &Connection->SendRequest, &Bucket->Entry );
break;
} else {
TI_DbgPrint(DEBUG_TCP,
("Completing Send request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Sent : 0;
InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
}
}
}
ReferenceObject(Connection);
if (ClientInfo.Unlocked)
{
UnlockObjectFromDpcLevel(Connection);
KeReleaseSpinLock(&ClientInfo.Lock, ClientInfo.OldIrql);
}
else
{
UnlockObject(Connection, Connection->OldIrql);
}
while ((Entry = ExInterlockedRemoveHeadList(&Connection->CompletionQueue,
&Connection->Lock)))
{
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Complete = Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
}
if (!ClientInfo.Unlocked)
{
LockObject(Connection, &OldIrql);
}
else
{
KeAcquireSpinLock(&ClientInfo.Lock, &ClientInfo.OldIrql);
}
DereferenceObject(Connection);
/* If the socket is dead, remove the reference we added for oskit */
if (Connection->SignalState & SEL_FIN)
{
Connection->SocketContext = NULL;
DereferenceObject(Connection);
}
}
#include "rosip.h"
VOID ConnectionFree(PVOID Object) {
PCONNECTION_ENDPOINT Connection = Object;
KIRQL OldIrql;
TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
DbgPrint("CONNECTION ENDPOINT: Freeing 0x%x\n", Object);
TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
RemoveEntryList(&Connection->ListEntry);
@ -270,13 +55,11 @@ PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
InitializeListHead(&Connection->ListenRequest);
InitializeListHead(&Connection->ReceiveRequest);
InitializeListHead(&Connection->SendRequest);
InitializeListHead(&Connection->CompletionQueue);
/* Save client context pointer */
Connection->ClientContext = ClientContext;
/* Add an extra reference for oskit */
Connection->RefCount = 2;
Connection->RefCount = 1;
Connection->Free = ConnectionFree;
/* Add connection endpoint to global list */
@ -298,16 +81,11 @@ NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
"Proto %d\n",
Connection, Family, Type, Proto));
Status = TCPTranslateError( OskitTCPSocket( Connection,
&Connection->SocketContext,
Family,
Type,
Proto ) );
ASSERT_KM_POINTER(Connection->SocketContext);
TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
Connection->SocketContext));
Connection->SocketContext = LibTCPSocket(Connection);
if (Connection->SocketContext)
Status = STATUS_SUCCESS;
else
Status = STATUS_INSUFFICIENT_RESOURCES;
UnlockObject(Connection, OldIrql);
@ -323,110 +101,13 @@ VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
* This is the low level interface for receiving TCP data
*/
{
KIRQL OldIrql;
DbgPrint("Got packet from network stack\n");
TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n",
TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to lwIP\n",
IPPacket->TotalSize,
IPPacket->HeaderSize));
KeAcquireSpinLock(&ClientInfo.Lock, &OldIrql);
ClientInfo.Unlocked = TRUE;
ClientInfo.OldIrql = OldIrql;
OskitTCPReceiveDatagram( IPPacket->Header,
IPPacket->TotalSize,
IPPacket->HeaderSize );
ClientInfo.Unlocked = FALSE;
KeReleaseSpinLock(&ClientInfo.Lock, OldIrql);
}
/* event.c */
int TCPSocketState( void *ClientData,
void *WhichSocket,
void *WhichConnection,
OSK_UINT NewState );
int TCPPacketSend( void *ClientData,
OSK_PCHAR Data,
OSK_UINT Len );
POSK_IFADDR TCPFindInterface( void *ClientData,
OSK_UINT AddrType,
OSK_UINT FindType,
OSK_SOCKADDR *ReqAddr );
NTSTATUS TCPMemStartup( void );
void *TCPMalloc( void *ClientData,
OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line );
void TCPFree( void *ClientData,
void *data, OSK_PCHAR file, OSK_UINT line );
void TCPMemShutdown( void );
OSKITTCP_EVENT_HANDLERS EventHandlers = {
NULL, /* Client Data */
TCPSocketState, /* SocketState */
TCPPacketSend, /* PacketSend */
TCPFindInterface, /* FindInterface */
TCPMalloc, /* Malloc */
TCPFree, /* Free */
NULL, /* Sleep */
NULL, /* Wakeup */
};
static KEVENT TimerLoopEvent;
static HANDLE TimerThreadHandle;
/*
* We are running 2 timers here, one with a 200ms interval (fast) and the other
* with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
* 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
* "slow" events at 500 and 1000.
*/
static VOID NTAPI
TimerThread(PVOID Context)
{
LARGE_INTEGER Timeout;
NTSTATUS Status;
unsigned Current, NextFast, NextSlow, Next;
Current = 0;
Next = 0;
NextFast = 0;
NextSlow = 0;
while ( 1 ) {
if (Next == NextFast) {
NextFast += 2;
}
if (Next == NextSlow) {
NextSlow += 5;
}
Next = min(NextFast, NextSlow);
Timeout.QuadPart = (LONGLONG) (Next - Current) * -1000000; /* 100 ms */
Status = KeWaitForSingleObject(&TimerLoopEvent, Executive, KernelMode,
FALSE, &Timeout);
if (Status != STATUS_TIMEOUT) {
PsTerminateSystemThread(Status);
}
TimerOskitTCP( Next == NextFast, Next == NextSlow );
Current = Next;
if (10 <= Current) {
Current = 0;
Next = 0;
NextFast = 0;
NextSlow = 0;
}
}
}
static VOID
StartTimer(VOID)
{
KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE);
PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0,
TimerThread, NULL);
LibIPInsertPacket(Interface->TCPContext, IPPacket->Header, IPPacket->TotalSize);
}
NTSTATUS TCPStartup(VOID)
@ -438,37 +119,17 @@ NTSTATUS TCPStartup(VOID)
{
NTSTATUS Status;
Status = TCPMemStartup();
if ( ! NT_SUCCESS(Status) ) {
return Status;
}
Status = PortsStartup( &TCPPorts, 1, 0xfffe );
if( !NT_SUCCESS(Status) ) {
TCPMemShutdown();
return Status;
}
KeInitializeSpinLock(&ClientInfo.Lock);
ClientInfo.Unlocked = FALSE;
RegisterOskitTCPEventHandlers( &EventHandlers );
InitOskitTCP();
/* Initialize our IP library */
LibIPInitialize();
/* Register this protocol with IP layer */
IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
ExInitializeNPagedLookasideList(
&TCPSegmentList, /* Lookaside list */
NULL, /* Allocate routine */
NULL, /* Free routine */
0, /* Flags */
sizeof(TCP_SEGMENT), /* Size of each entry */
'SPCT', /* Tag */
0); /* Depth */
StartTimer();
TCPInitialized = TRUE;
return STATUS_SUCCESS;
@ -482,59 +143,50 @@ NTSTATUS TCPShutdown(VOID)
* Status of operation
*/
{
LARGE_INTEGER WaitForThread;
if (!TCPInitialized)
return STATUS_SUCCESS;
WaitForThread.QuadPart = -2500000; /* 250 ms */
KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE);
ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread);
LibIPShutdown();
/* Deregister this protocol with IP layer */
IPRegisterProtocol(IPPROTO_TCP, NULL);
ExDeleteNPagedLookasideList(&TCPSegmentList);
TCPInitialized = FALSE;
DeinitOskitTCP();
PortsShutdown( &TCPPorts );
TCPMemShutdown();
return STATUS_SUCCESS;
}
NTSTATUS TCPTranslateError( int OskitError ) {
NTSTATUS TCPTranslateError( err_t err ) {
NTSTATUS Status;
switch( OskitError ) {
case 0: Status = STATUS_SUCCESS; break;
case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break;
case OSK_EADDRINUSE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break;
case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break;
case OSK_ECONNREFUSED: Status = STATUS_REMOTE_NOT_LISTENING; break;
case OSK_ECONNRESET: Status = STATUS_REMOTE_DISCONNECT; break;
case OSK_ECONNABORTED: Status = STATUS_LOCAL_DISCONNECT; break;
case OSK_EWOULDBLOCK:
case OSK_EINPROGRESS: Status = STATUS_PENDING; break;
case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; break;
case OSK_ENOMEM:
case OSK_ENOBUFS: Status = STATUS_INSUFFICIENT_RESOURCES; break;
case OSK_ESHUTDOWN: Status = STATUS_FILE_CLOSED; break;
case OSK_EMSGSIZE: Status = STATUS_BUFFER_TOO_SMALL; break;
case OSK_ETIMEDOUT: Status = STATUS_TIMEOUT; break;
case OSK_ENETUNREACH: Status = STATUS_NETWORK_UNREACHABLE; break;
case OSK_EFAULT: Status = STATUS_ACCESS_VIOLATION; break;
default:
DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError);
Status = STATUS_INVALID_CONNECTION;
break;
switch (err)
{
case ERR_OK: Status = STATUS_SUCCESS; break; //0
case ERR_MEM: Status = STATUS_INSUFFICIENT_RESOURCES; break; //-1
case ERR_BUF: Status = STATUS_BUFFER_TOO_SMALL; break; //-2
case ERR_TIMEOUT: Status = STATUS_TIMEOUT; break; // -3
case ERR_RTE: Status = STATUS_HOST_UNREACHABLE; break; //-4
case ERR_ABRT: Status = STATUS_LOCAL_DISCONNECT; break; //-5
case ERR_RST: Status = STATUS_REMOTE_DISCONNECT; break; //-6
case ERR_CLSD: Status = STATUS_FILE_CLOSED; break; //-7
case ERR_CONN: Status = STATUS_UNSUCCESSFUL; break; //-8 (FIXME)
case ERR_VAL: Status = STATUS_INVALID_PARAMETER; break; //-9
case ERR_ARG: Status = STATUS_INVALID_PARAMETER; break; //-10
case ERR_USE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; //-11
case ERR_IF: Status = STATUS_NETWORK_UNREACHABLE; break; //-12
case ERR_ISCONN: Status = STATUS_UNSUCCESSFUL; break; //-13 (FIXME)
case ERR_INPROGRESS: Status = STATUS_PENDING; break; //-14
default:
DbgPrint("Invalid error value: %d\n", err);
ASSERT(FALSE);
Status = STATUS_UNSUCCESSFUL;
break;
}
TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status));
DbgPrint("TCPTranslateError: %d -> %x\n", (unsigned int)err, Status);
return Status;
}
@ -545,7 +197,7 @@ NTSTATUS TCPConnect
PTCP_COMPLETION_ROUTINE Complete,
PVOID Context ) {
NTSTATUS Status;
SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
struct ip_addr bindaddr, connaddr;
IP_ADDRESS RemoteAddress;
USHORT RemotePort;
PTDI_BUCKET Bucket;
@ -570,9 +222,6 @@ NTSTATUS TCPConnect
RemoteAddress.Address.IPv4Address,
RemotePort));
AddressToConnect.sin_family = AF_INET;
AddressToBind = AddressToConnect;
LockObject(Connection, &OldIrql);
if (!Connection->AddressFile)
@ -589,28 +238,27 @@ NTSTATUS TCPConnect
return STATUS_NETWORK_UNREACHABLE;
}
AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address;
bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address;
}
else
{
AddressToBind.sin_addr.s_addr = Connection->AddressFile->Address.Address.IPv4Address;
bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address;
}
Status = TCPTranslateError
( OskitTCPBind( Connection->SocketContext,
&AddressToBind,
sizeof(AddressToBind) ) );
Status = TCPTranslateError(LibTCPBind(Connection->SocketContext,
&bindaddr,
Connection->AddressFile->Port));
DbgPrint("LibTCPBind: 0x%x\n", Status);
if (NT_SUCCESS(Status)) {
memcpy( &AddressToConnect.sin_addr,
&RemoteAddress.Address.IPv4Address,
sizeof(AddressToConnect.sin_addr) );
AddressToConnect.sin_port = RemotePort;
Status = TCPTranslateError
( OskitTCPConnect( Connection->SocketContext,
&AddressToConnect,
sizeof(AddressToConnect) ) );
connaddr.addr = RemoteAddress.Address.IPv4Address;
Status = TCPTranslateError(LibTCPConnect(Connection->SocketContext,
&connaddr,
RemotePort));
DbgPrint("LibTCPConnect: 0x%x\n", Status);
if (Status == STATUS_PENDING)
{
@ -648,10 +296,20 @@ NTSTATUS TCPDisconnect
LockObject(Connection, &OldIrql);
if (Flags & TDI_DISCONNECT_RELEASE)
Status = TCPTranslateError(OskitTCPDisconnect(Connection->SocketContext));
{
/* FIXME */
LibTCPClose(Connection->SocketContext);
}
if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
Status = TCPTranslateError(OskitTCPShutdown(Connection->SocketContext, FWRITE | FREAD));
{
/* FIXME */
LibTCPClose(Connection->SocketContext);
}
Status = STATUS_SUCCESS;
DbgPrint("LibTCPClose: %x\n", Status);
UnlockObject(Connection, OldIrql);
@ -664,7 +322,6 @@ NTSTATUS TCPClose
( PCONNECTION_ENDPOINT Connection )
{
KIRQL OldIrql;
NTSTATUS Status;
PVOID Socket;
PADDRESS_FILE AddressFile = NULL;
PCONNECTION_ENDPOINT AddressConnection = NULL;
@ -676,21 +333,9 @@ NTSTATUS TCPClose
/* Don't try to close again if the other side closed us already */
if (Socket)
{
/* We need to close here otherwise oskit will never indicate
* SEL_FIN and we will never fully close the connection */
Status = TCPTranslateError( OskitTCPClose( Socket ) );
if (!NT_SUCCESS(Status))
{
Connection->SocketContext = Socket;
UnlockObject(Connection, OldIrql);
return Status;
}
}
else
{
/* We are already closed by the other end so return success */
Status = STATUS_SUCCESS;
LibTCPClose(Socket);
FlushAllQueues(Connection, STATUS_CANCELLED);
}
if (Connection->AddressFile)
@ -715,7 +360,7 @@ NTSTATUS TCPClose
if (AddressFile)
DereferenceObject(AddressFile);
return Status;
return STATUS_SUCCESS;
}
NTSTATUS TCPReceiveData
@ -726,57 +371,32 @@ NTSTATUS TCPReceiveData
ULONG ReceiveFlags,
PTCP_COMPLETION_ROUTINE Complete,
PVOID Context ) {
PVOID DataBuffer;
UINT DataLen, Received = 0;
NTSTATUS Status;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
ReceiveLength, Connection->SocketContext));
NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
LockObject(Connection, &OldIrql);
Status = TCPTranslateError
( OskitTCPRecv
( Connection->SocketContext,
DataBuffer,
DataLen,
&Received,
ReceiveFlags ) );
TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received));
/* Keep this request around ... there was no data yet */
if( Status == STATUS_PENDING ) {
/* Freed in TCPSocketState */
Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
if( !Bucket ) {
TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
UnlockObject(Connection, OldIrql);
return STATUS_NO_MEMORY;
}
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
*BytesReceived = 0;
InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry );
TI_DbgPrint(DEBUG_TCP,("Queued read irp\n"));
} else {
TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received));
*BytesReceived = Received;
/* Freed in TCPSocketState */
Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
if( !Bucket ) {
TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
UnlockObject(Connection, OldIrql);
return STATUS_NO_MEMORY;
}
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
*BytesReceived = 0;
InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry );
TI_DbgPrint(DEBUG_TCP,("Queued read irp\n"));
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
return Status;
return STATUS_PENDING;
}
NTSTATUS TCPSendData
@ -787,7 +407,6 @@ NTSTATUS TCPSendData
ULONG Flags,
PTCP_COMPLETION_ROUTINE Complete,
PVOID Context ) {
UINT Sent = 0;
NTSTATUS Status;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
@ -801,12 +420,13 @@ NTSTATUS TCPSendData
TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
Connection->SocketContext));
Status = TCPTranslateError
( OskitTCPSend( Connection->SocketContext,
(OSK_PCHAR)BufferData, SendLength,
&Sent, 0 ) );
Status = TCPTranslateError(LibTCPSend(Connection->SocketContext,
BufferData,
SendLength));
DbgPrint("LibTCPSend: 0x%x\n", Status);
TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
TI_DbgPrint(DEBUG_TCP,("Send: %x, %d\n", Status, SendLength));
/* Keep this request around ... there was no data yet */
if( Status == STATUS_PENDING ) {
@ -825,8 +445,8 @@ NTSTATUS TCPSendData
InsertTailList( &Connection->SendRequest, &Bucket->Entry );
TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
} else {
TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
*BytesSent = Sent;
TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, SendLength));
*BytesSent = SendLength;
}
UnlockObject(Connection, OldIrql);
@ -855,28 +475,35 @@ NTSTATUS TCPGetSockAddress
( PCONNECTION_ENDPOINT Connection,
PTRANSPORT_ADDRESS Address,
BOOLEAN GetRemote ) {
OSK_UINT LocalAddress, RemoteAddress;
OSK_UI16 LocalPort, RemotePort;
PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
struct ip_addr ipaddr;
NTSTATUS Status;
KIRQL OldIrql;
LockObject(Connection, &OldIrql);
Status = TCPTranslateError(OskitTCPGetAddress(Connection->SocketContext,
&LocalAddress, &LocalPort,
&RemoteAddress, &RemotePort));
UnlockObject(Connection, OldIrql);
if (!NT_SUCCESS(Status))
return Status;
AddressIP->TAAddressCount = 1;
AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
AddressIP->Address[0].Address[0].sin_port = GetRemote ? RemotePort : LocalPort;
AddressIP->Address[0].Address[0].in_addr = GetRemote ? RemoteAddress : LocalAddress;
LockObject(Connection, &OldIrql);
if (GetRemote)
{
Status = TCPTranslateError(LibTCPGetPeerName(Connection->SocketContext,
&ipaddr,
&AddressIP->Address[0].Address[0].sin_port));
}
else
{
Status = TCPTranslateError(LibTCPGetHostName(Connection->SocketContext,
&ipaddr,
&AddressIP->Address[0].Address[0].sin_port));
}
UnlockObject(Connection, OldIrql);
AddressIP->Address[0].Address[0].in_addr = ipaddr.addr;
DbgPrint("LibTCPGetXXXName: 0x%x\n", Status);
return Status;
}

37
lib/drivers/lwip/lwip.rbuild Executable file
View file

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
<module name="lwip" type="staticlibrary">
<include base="lwip">src/include</include>
<include base="lwip">src/include/ipv4</include>
<directory name="src">
<file>rosip.c</file>
<file>rostcp.c</file>
<file>rosmem.c</file>
<file>sys_arch.c</file>
<directory name="api">
<file>err.c</file>
<file>netbuf.c</file>
<file>netifapi.c</file>
<file>tcpip.c</file>
</directory>
<directory name="core">
<file>init.c</file>
<file>mem.c</file>
<file>memp.c</file>
<file>netif.c</file>
<file>pbuf.c</file>
<file>stats.c</file>
<file>sys.c</file>
<file>tcp_in.c</file>
<file>tcp_out.c</file>
<file>tcp.c</file>
<directory name="ipv4">
<file>inet_chksum.c</file>
<file>inet.c</file>
<file>ip.c</file>
<file>ip_addr.c</file>
<file>ip_frag.c</file>
</directory>
</directory>
</directory>
</module>

View file

@ -0,0 +1 @@
#pragma pack(push,1)

View file

@ -0,0 +1,63 @@
/* ReactOS-Specific lwIP binding header - by Cameron Gutman */
#include <wdm.h>
#define LWIP_PROVIDE_ERRNO
/* ROS-specific mem defs */
void *
malloc(size_t size);
void *
calloc(size_t count, size_t size);
void
free(void *mem);
void *
realloc(void *mem, size_t size);
#define mem_realloc(_m_, _s_) realloc(_m_, _s_)
/* Unsigned int types */
typedef unsigned char u8_t;
typedef unsigned short u16_t;
typedef unsigned long u32_t;
/* Signed int types */
typedef signed char s8_t;
typedef signed short s16_t;
typedef signed long s32_t;
/* Memory pointer */
typedef u32_t mem_ptr_t;
/* Printf/DPRINT formatters */
#define U16_F "hu"
#define S16_F "hd"
#define X16_F "hx"
#define U32_F "lu"
#define S32_F "ld"
#define X32_F "lx"
/* Endianness */
#define BYTE_ORDER LITTLE_ENDIAN
/* Checksum calculation algorithm choice */
#define LWIP_CHKSUM_ALGORITHM 3
/* Diagnostics */
#define LWIP_PLATFORM_DIAG(x) DbgPrint(x)
#define LWIP_PLATFORM_ASSERT(x) ASSERTMSG(x, FALSE)
/* Synchronization */
#define SYS_ARCH_DECL_PROTECT(lev) \
sys_prot_t lev; \
sys_arch_decl_protect(&lev)
#define SYS_ARCH_PROTECT(lev) sys_arch_protect(&lev)
#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(&lev)
/* Compiler hints for packing structures */
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_USE_INCLUDES

View file

@ -0,0 +1 @@
#pragma pack(pop)

View file

@ -0,0 +1,4 @@
/* ReactOS-Specific lwIP binding header - by Cameron Gutman */
#define PERF_START
#define PERF_STOP

View file

@ -0,0 +1,45 @@
/* ReactOS-Specific lwIP binding header - by Cameron Gutman */
/* Implmentation specific structs */
typedef PRKEVENT sys_sem_t;
typedef struct _sys_mbox_t
{
KSPIN_LOCK Lock;
LIST_ENTRY ListHead;
KEVENT Event;
} *sys_mbox_t;
typedef struct _sys_prot_t
{
KSPIN_LOCK Lock;
KIRQL OldIrql;
} sys_prot_t;
typedef u32_t sys_thread_t;
typedef struct _LWIP_MESSAGE_CONTAINER
{
PVOID Message;
LIST_ENTRY ListEntry;
} LWIP_MESSAGE_CONTAINER, *PLWIP_MESSAGE_CONTAINER;
#define sys_jiffies() sys_now()
/* NULL definitions */
#define SYS_MBOX_NULL NULL
#define SYS_SEM_NULL NULL
#define SYS_ARCH_NULL NULL
void
sys_arch_protect(sys_prot_t *lev);
void
sys_arch_unprotect(sys_prot_t *lev);
void
sys_arch_decl_protect(sys_prot_t *lev);
void
sys_shutdown(void);

View file

@ -0,0 +1,194 @@
/*
------------------------------------
---------- Memory options ----------
------------------------------------
*/
/* This combo allows us to implement malloc, free, and realloc ourselves */
#define MEM_LIBC_MALLOC 1
#define MEMP_MEM_MALLOC 1
#define MEM_ALIGNMENT 4
#define LWIP_ARP 0
#define ARP_QUEUEING 0
#define IP_FORWARD 0
#define IP_REASS_MAX_PBUFS 0xFFFFFFFF
#define IP_DEFAULT_TTL 128
#define IP_SOF_BROADCAST 1
#define IP_SOF_BROADCAST_RECV 1
#define LWIP_ICMP 0
#define LWIP_RAW 0
#define LWIP_DHCP 0
#define LWIP_AUTOIP 0
#define LWIP_SNMP 0
#define LWIP_IGMP 0
#define LWIP_DNS 0
#define LWIP_UDP 0
#define LWIP_UDPLITE 0
#define LWIP_TCP 1
#define TCP_QUEUE_OOSEQ 1
#define TCP_MSS 1024
#define TCP_SND_BUF (TCP_MSS * 8)
#define TCP_SND_QUEUELEN (8 * (TCP_SND_BUF / TCP_MSS))
#define TCP_SNDLOWAT TCP_MSS
#define TCP_WND 0xFFFF
#define TCP_MAXRTX 12
#define TCP_SYNMAXRTX 4
#define TCP_LISTEN_BACKLOG 1
#define LWIP_TCP_TIMESTAMPS 1
#define LWIP_CALLBACK_API 1
#define LWIP_NETIF_API 1
#define LWIP_SOCKET 0
#define LWIP_NETCONN 0
#define LWIP_NETIF_HWADDRHINT 0
#define LWIP_STATS 0
#define ICMP_STATS 0
#define PPP_SUPPORT 0
#define PPPOE_SUPPORT 0
#define PPPOS_SUPPORT 0
/*
---------------------------------------
---------- Debugging options ----------
---------------------------------------
*/
/**
* LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is
* compared against this value. If it is smaller, then debugging
* messages are written.
*/
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
/**
* LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable
* debug messages of certain types.
*/
#define LWIP_DBG_TYPES_ON LWIP_DBG_ON
/**
* NETIF_DEBUG: Enable debugging in netif.c.
*/
#define NETIF_DEBUG LWIP_DBG_OFF
/**
* PBUF_DEBUG: Enable debugging in pbuf.c.
*/
#define PBUF_DEBUG LWIP_DBG_OFF
/**
* INET_DEBUG: Enable debugging in inet.c.
*/
#define INET_DEBUG LWIP_DBG_OFF
/**
* IP_DEBUG: Enable debugging for IP.
*/
#define IP_DEBUG LWIP_DBG_OFF
/**
* IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass.
*/
#define IP_REASS_DEBUG LWIP_DBG_OFF
/**
* MEM_DEBUG: Enable debugging in mem.c.
*/
#define MEM_DEBUG LWIP_DBG_OFF
/**
* MEMP_DEBUG: Enable debugging in memp.c.
*/
#define MEMP_DEBUG LWIP_DBG_OFF
/**
* SYS_DEBUG: Enable debugging in sys.c.
*/
#define SYS_DEBUG LWIP_DBG_OFF
/**
* TCP_DEBUG: Enable debugging for TCP.
*/
#define TCP_DEBUG LWIP_DBG_OFF
/**
* TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.
*/
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
/**
* TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit.
*/
#define TCP_FR_DEBUG LWIP_DBG_OFF
/**
* TCP_RTO_DEBUG: Enable debugging in TCP for retransmit
* timeout.
*/
#define TCP_RTO_DEBUG LWIP_DBG_OFF
/**
* TCP_CWND_DEBUG: Enable debugging for TCP congestion window.
*/
#define TCP_CWND_DEBUG LWIP_DBG_OFF
/**
* TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating.
*/
#define TCP_WND_DEBUG LWIP_DBG_OFF
/**
* TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.
*/
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
/**
* TCP_RST_DEBUG: Enable debugging for TCP with the RST message.
*/
#define TCP_RST_DEBUG LWIP_DBG_OFF
/**
* TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths.
*/
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
/**
* TCPIP_DEBUG: Enable debugging in tcpip.c.
*/
#define TCPIP_DEBUG LWIP_DBG_OFF

View file

@ -0,0 +1,31 @@
#ifndef _ROS_IP_H_
#define _ROS_IP_H_
#include "lwip/tcp.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
/* External TCP event handlers */
extern void TCPConnectEventHandler(void *arg, err_t err);
extern void TCPAcceptEventHandler(void *arg, struct tcp_pcb *newpcb);
extern void TCPSendEventHandler(void *arg, u16_t space);
extern void TCPFinEventHandler(void *arg, err_t err);
extern u32_t TCPRecvEventHandler(void *arg, struct pbuf *p);
/* TCP functions */
struct tcp_pcb *LibTCPSocket(void *arg);
err_t LibTCPBind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port);
struct tcp_pcb *LibTCPListen(struct tcp_pcb *pcb, u8_t backlog);
err_t LibTCPSend(struct tcp_pcb *pcb, void *dataptr, u16_t len);
err_t LibTCPConnect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port);
err_t LibTCPClose(struct tcp_pcb *pcb);
err_t LibTCPGetPeerName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port);
err_t LibTCPGetHostName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port);
void LibTCPAccept(struct tcp_pcb *pcb, void *arg);
/* IP functions */
void LibIPInsertPacket(void *ifarg, void *data, u32_t size);
void LibIPInitialize(void);
void LibIPShutdown(void);
#endif

45
lib/drivers/lwip/src/rosip.c Executable file
View file

@ -0,0 +1,45 @@
#include "lwip/sys.h"
#include "lwip/tcpip.h"
#include "rosip.h"
#include <debug.h>
void
LibIPInsertPacket(void *ifarg,
void *data,
u32_t size)
{
struct pbuf *p, *p1;
u32_t i;
ASSERT(ifarg);
ASSERT(data);
ASSERT(size > 0);
p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_POOL);
if (p)
{
for (i = 0, p1 = p; i < size; i += p1->len, p1 = p1->next)
{
ASSERT(p1);
RtlCopyMemory(p1->payload, ((PUCHAR)data) + i, p1->len);
}
((struct netif *)ifarg)->input(p, ifarg);
}
}
void
LibIPInitialize(void)
{
/* This completes asynchronously */
tcpip_init(NULL, NULL);
}
void
LibIPShutdown(void)
{
/* This is synchronous */
sys_shutdown();
}

38
lib/drivers/lwip/src/rosmem.c Executable file
View file

@ -0,0 +1,38 @@
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#define LWIP_TAG 'PIwl'
void *
malloc(mem_size_t size)
{
return ExAllocatePoolWithTag(NonPagedPool, size, LWIP_TAG);
}
void *
calloc(mem_size_t count, mem_size_t size)
{
void *mem = malloc(count * size);
if (!mem) return NULL;
RtlZeroMemory(mem, count * size);
return mem;
}
void
free(void *mem)
{
ExFreePoolWithTag(mem, LWIP_TAG);
}
void *
realloc(void *mem, size_t size)
{
free(mem);
return malloc(size);
}

581
lib/drivers/lwip/src/rostcp.c Executable file
View file

@ -0,0 +1,581 @@
#include "lwip/sys.h"
#include "lwip/tcpip.h"
#include "rosip.h"
#include <debug.h>
/* The way that lwIP does multi-threading is really not ideal for our purposes but
* we best go along with it unless we want another unstable TCP library. lwIP uses
* a thread called the "tcpip thread" which is the only one allowed to call raw API
* functions. Since this is the case, for each of our LibTCP* functions, we queue a request
* for a callback to "tcpip thread" which calls our LibTCP*Callback functions. Yes, this is
* a lot of unnecessary thread swapping and it could definitely be faster, but I don't want
* to going messing around in lwIP because I have no desire to create another mess like oskittcp */
extern KEVENT TerminationEvent;
static
BOOLEAN
WaitForEventSafely(PRKEVENT Event)
{
PVOID WaitObjects[] = {Event, &TerminationEvent};
if (KeWaitForMultipleObjects(2,
WaitObjects,
WaitAny,
Executive,
KernelMode,
FALSE,
NULL,
NULL) == STATUS_WAIT_0)
{
/* Signalled by the caller's event */
return TRUE;
}
else /* if KeWaitForMultipleObjects() == STATUS_WAIT_1 */
{
/* Signalled by our termination event */
return FALSE;
}
}
static
err_t
InternalSendEventHandler(void *arg, struct tcp_pcb *pcb, u16_t space)
{
DbgPrint("SendEvent(0x%x, 0x%x, %d)\n", arg, pcb, (unsigned int)space);
/* Make sure the socket didn't get closed */
if (!arg) return ERR_OK;
TCPSendEventHandler(arg, space);
return ERR_OK;
}
static
err_t
InternalRecvEventHandler(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
u32_t len;
DbgPrint("RecvEvent(0x%x, 0x%x, 0x%x, %d)\n", arg, pcb, p, (unsigned int)err);
/* Make sure the socket didn't get closed */
if (!arg)
{
if (p) pbuf_free(p);
return ERR_OK;
}
if (!p)
{
TCPFinEventHandler(arg, ERR_OK);
}
else
{
DbgPrint("RECV - p:0x%x p->payload:0x%x p->len:%d p->tot_len:%d\n", p, p->payload, p->len, p->tot_len);
if (err == ERR_OK)
{
len = TCPRecvEventHandler(arg, p);
if (len != 0)
{
tcp_recved(pcb, len);
pbuf_free(p);
return ERR_OK;
}
else
{
/* We want lwIP to store the pbuf on its queue for later */
return ERR_TIMEOUT;
}
}
else
{
pbuf_free(p);
}
}
return ERR_OK;
}
static
err_t
InternalAcceptEventHandler(void *arg, struct tcp_pcb *newpcb, err_t err)
{
DbgPrint("AcceptEvent(0x%x, 0x%x, %d)\n", arg, newpcb, (unsigned int)err);
/* Make sure the socket didn't get closed */
if (!arg) return ERR_ABRT;
TCPAcceptEventHandler(arg, newpcb);
/* Set in LibTCPAccept (called from TCPAcceptEventHandler) */
if (newpcb->callback_arg)
return ERR_OK;
else
return ERR_ABRT;
}
static
err_t
InternalConnectEventHandler(void *arg, struct tcp_pcb *pcb, err_t err)
{
DbgPrint("ConnectEvent(0x%x, 0x%x, %d)\n", arg, pcb, (unsigned int)err);
/* Make sure the socket didn't get closed */
if (!arg) return ERR_OK;
TCPConnectEventHandler(arg, err);
tcp_recv(pcb, InternalRecvEventHandler);
return ERR_OK;
}
static
void
InternalErrorEventHandler(void *arg, err_t err)
{
DbgPrint("ErrorEvent(0x%x, %d)\n", arg, (unsigned int)err);
/* Make sure the socket didn't get closed */
if (!arg) return;
TCPFinEventHandler(arg, err);
}
struct socket_callback_msg
{
/* Synchronization */
KEVENT Event;
/* Input */
PVOID Arg;
/* Output */
PVOID NewPcb;
};
static
void
LibTCPSocketCallback(void *arg)
{
struct socket_callback_msg *msg = arg;
ASSERT(msg);
msg->NewPcb = tcp_new();
if (msg->NewPcb)
{
tcp_arg(msg->NewPcb, msg->Arg);
tcp_err(msg->NewPcb, InternalErrorEventHandler);
}
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
}
struct tcp_pcb *
LibTCPSocket(void *arg)
{
struct socket_callback_msg *msg = ExAllocatePool(NonPagedPool, sizeof(struct socket_callback_msg));
void *ret;
if (msg)
{
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
msg->Arg = arg;
tcpip_callback_with_block(LibTCPSocketCallback, msg, 1);
if (WaitForEventSafely(&msg->Event))
ret = msg->NewPcb;
else
ret = NULL;
DbgPrint("LibTCPSocket(0x%x) = 0x%x\n", arg, ret);
ExFreePool(msg);
return ret;
}
return NULL;
}
struct bind_callback_msg
{
/* Synchronization */
KEVENT Event;
/* Input */
struct tcp_pcb *Pcb;
struct ip_addr *IpAddress;
u16_t Port;
/* Output */
err_t Error;
};
static
void
LibTCPBindCallback(void *arg)
{
struct bind_callback_msg *msg = arg;
ASSERT(msg);
msg->Error = tcp_bind(msg->Pcb, msg->IpAddress, ntohs(msg->Port));
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
}
err_t
LibTCPBind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
{
struct bind_callback_msg *msg;
err_t ret;
if (!pcb)
return ERR_CLSD;
msg = ExAllocatePool(NonPagedPool, sizeof(struct bind_callback_msg));
if (msg)
{
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
msg->Pcb = pcb;
msg->IpAddress = ipaddr;
msg->Port = port;
tcpip_callback_with_block(LibTCPBindCallback, msg, 1);
if (WaitForEventSafely(&msg->Event))
ret = msg->Error;
else
ret = ERR_CLSD;
DbgPrint("LibTCPBind(0x%x)\n", pcb);
ExFreePool(msg);
return ret;
}
return ERR_MEM;
}
struct listen_callback_msg
{
/* Synchronization */
KEVENT Event;
/* Input */
struct tcp_pcb *Pcb;
u8_t Backlog;
/* Output */
struct tcp_pcb *NewPcb;
};
static
void
LibTCPListenCallback(void *arg)
{
struct listen_callback_msg *msg = arg;
void *p;
ASSERT(msg);
p = msg->Pcb->callback_arg;
msg->NewPcb = tcp_listen_with_backlog(msg->Pcb, msg->Backlog);
if (msg->NewPcb)
{
tcp_arg(msg->NewPcb, p);
tcp_accept(msg->NewPcb, InternalAcceptEventHandler);
tcp_err(msg->NewPcb, InternalErrorEventHandler);
}
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
}
struct tcp_pcb *
LibTCPListen(struct tcp_pcb *pcb, u8_t backlog)
{
struct listen_callback_msg *msg;
void *ret;
if (!pcb)
return NULL;
msg = ExAllocatePool(NonPagedPool, sizeof(struct listen_callback_msg));
if (msg)
{
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
msg->Pcb = pcb;
msg->Backlog = backlog;
tcpip_callback_with_block(LibTCPListenCallback, msg, 1);
if (WaitForEventSafely(&msg->Event))
ret = msg->NewPcb;
else
ret = NULL;
DbgPrint("LibTCPListen(0x%x,0x%x)\n", pcb, ret);
ExFreePool(msg);
return ret;
}
return NULL;
}
struct send_callback_msg
{
/* Synchronization */
KEVENT Event;
/* Input */
struct tcp_pcb *Pcb;
void *Data;
u16_t DataLength;
/* Output */
err_t Error;
};
static
void
LibTCPSendCallback(void *arg)
{
struct send_callback_msg *msg = arg;
ASSERT(msg);
if (tcp_sndbuf(msg->Pcb) < msg->DataLength)
{
msg->Error = ERR_INPROGRESS;
}
else
{
tcp_sent(msg->Pcb, InternalSendEventHandler);
msg->Error = tcp_write(msg->Pcb, msg->Data, msg->DataLength, TCP_WRITE_FLAG_COPY);
tcp_output(msg->Pcb);
}
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
}
err_t
LibTCPSend(struct tcp_pcb *pcb, void *dataptr, u16_t len)
{
struct send_callback_msg *msg;
err_t ret;
if (!pcb)
return ERR_CLSD;
msg = ExAllocatePool(NonPagedPool, sizeof(struct send_callback_msg));
if (msg)
{
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
msg->Pcb = pcb;
msg->Data = dataptr;
msg->DataLength = len;
tcpip_callback_with_block(LibTCPSendCallback, msg, 1);
if (WaitForEventSafely(&msg->Event))
ret = msg->Error;
else
ret = ERR_CLSD;
DbgPrint("LibTCPSend(0x%x)\n", pcb);
ExFreePool(msg);
return ret;
}
return ERR_MEM;
}
struct connect_callback_msg
{
/* Synchronization */
KEVENT Event;
/* Input */
struct tcp_pcb *Pcb;
struct ip_addr *IpAddress;
u16_t Port;
/* Output */
err_t Error;
};
static
void
LibTCPConnectCallback(void *arg)
{
struct connect_callback_msg *msg = arg;
ASSERT(arg);
msg->Error = tcp_connect(msg->Pcb, msg->IpAddress, ntohs(msg->Port), InternalConnectEventHandler);
if (msg->Error == ERR_OK)
msg->Error = ERR_INPROGRESS;
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
}
err_t
LibTCPConnect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
{
struct connect_callback_msg *msg;
err_t ret;
if (!pcb)
return ERR_CLSD;
msg = ExAllocatePool(NonPagedPool, sizeof(struct connect_callback_msg));
if (msg)
{
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
msg->Pcb = pcb;
msg->IpAddress = ipaddr;
msg->Port = port;
tcpip_callback_with_block(LibTCPConnectCallback, msg, 1);
if (WaitForEventSafely(&msg->Event))
ret = msg->Error;
else
ret = ERR_CLSD;
ExFreePool(msg);
DbgPrint("LibTCPConnect(0x%x)\n", pcb);
return ret;
}
return ERR_MEM;
}
struct close_callback_msg
{
/* Synchronization */
KEVENT Event;
/* Input */
struct tcp_pcb *Pcb;
/* Output */
err_t Error;
};
static
void
LibTCPCloseCallback(void *arg)
{
struct close_callback_msg *msg = arg;
msg->Error = tcp_close(msg->Pcb);
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
}
err_t
LibTCPClose(struct tcp_pcb *pcb)
{
struct close_callback_msg *msg;
err_t ret;
if (!pcb)
return ERR_CLSD;
tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_err(pcb, NULL);
tcp_accept(pcb, NULL);
msg = ExAllocatePool(NonPagedPool, sizeof(struct close_callback_msg));
if (msg)
{
KeInitializeEvent(&msg->Event, NotificationEvent, FALSE);
msg->Pcb = pcb;
tcpip_callback_with_block(LibTCPCloseCallback, msg, 1);
if (WaitForEventSafely(&msg->Event))
ret = msg->Error;
else
ret = ERR_CLSD;
ExFreePool(msg);
DbgPrint("LibTCPClose(0x%x)\n", pcb);
return ret;
}
return ERR_MEM;
}
void
LibTCPAccept(struct tcp_pcb *pcb, void *arg)
{
DbgPrint("LibTCPAccept(0x%x, 0x%x)\n", pcb, arg);
ASSERT(arg);
tcp_arg(pcb, NULL);
tcp_recv(pcb, InternalRecvEventHandler);
tcp_sent(pcb, InternalSendEventHandler);
tcp_arg(pcb, arg);
tcp_accepted(pcb);
}
err_t
LibTCPGetHostName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port)
{
DbgPrint("LibTCPGetHostName(0x%x)\n", pcb);
if (!pcb)
return ERR_CLSD;
*ipaddr = pcb->local_ip;
*port = pcb->local_port;
DbgPrint("Got host port: %d\n", *port);
return ERR_OK;
}
err_t
LibTCPGetPeerName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port)
{
DbgPrint("LibTCPGetPeerName(0x%x)\n", pcb);
if (!pcb)
return ERR_CLSD;
*ipaddr = pcb->remote_ip;
*port = pcb->remote_port;
DbgPrint("Got remote port: %d\n", *port);
return ERR_OK;
}

380
lib/drivers/lwip/src/sys_arch.c Executable file
View file

@ -0,0 +1,380 @@
#include "lwip/sys.h"
#include "lwip/tcp.h"
#include "lwip/pbuf.h"
#include "lwip/err.h"
#include <debug.h>
static LIST_ENTRY ThreadListHead;
static KSPIN_LOCK ThreadListLock;
KEVENT TerminationEvent;
static LARGE_INTEGER StartTime;
typedef struct _thread_t
{
PVOID ThreadId;
HANDLE Handle;
struct sys_timeouts Timeouts;
void (* ThreadFunction)(void *arg);
void *ThreadContext;
LIST_ENTRY ListEntry;
char Name[1];
} *thread_t;
u32_t sys_now(void)
{
LARGE_INTEGER CurrentTime;
KeQuerySystemTime(&CurrentTime);
return (CurrentTime.QuadPart - StartTime.QuadPart) / 10000;
}
void
sys_arch_protect(sys_prot_t *lev)
{
KIRQL OldIrql;
KeAcquireSpinLock(&lev->Lock, &OldIrql);
lev->OldIrql = OldIrql;
}
void
sys_arch_unprotect(sys_prot_t *lev)
{
KeReleaseSpinLock(&lev->Lock, lev->OldIrql);
}
void
sys_arch_decl_protect(sys_prot_t *lev)
{
KeInitializeSpinLock(&lev->Lock);
}
sys_sem_t
sys_sem_new(u8_t count)
{
sys_sem_t sem = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
if (!sem)
return SYS_SEM_NULL;
ASSERT(count == 0 || count == 1);
/* It seems lwIP uses the semaphore implementation as either a completion event or a lock
* so I optimize for this case by using a synchronization event and setting its initial state
* to signalled for a lock and non-signalled for a completion event */
KeInitializeEvent(sem, SynchronizationEvent, count);
return sem;
}
void
sys_sem_free(sys_sem_t sem)
{
ExFreePool(sem);
}
void
sys_sem_signal(sys_sem_t sem)
{
KeSetEvent(sem, IO_NO_INCREMENT, FALSE);
}
u32_t
sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
{
LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime;
UINT64 TimeDiff;
NTSTATUS Status;
PVOID WaitObjects[] = {sem, &TerminationEvent};
LargeTimeout.QuadPart = Int32x32To64(timeout, -10000);
KeQuerySystemTime(&PreWaitTime);
Status = KeWaitForMultipleObjects(2,
WaitObjects,
WaitAny,
Executive,
KernelMode,
FALSE,
timeout != 0 ? &LargeTimeout : NULL,
NULL);
if (Status == STATUS_WAIT_0)
{
KeQuerySystemTime(&PostWaitTime);
TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart;
TimeDiff /= 10000;
return TimeDiff;
}
else if (Status == STATUS_WAIT_1)
{
/* DON'T remove ourselves from the thread list! */
PsTerminateSystemThread(STATUS_SUCCESS);
/* We should never get here! */
ASSERT(FALSE);
return 0;
}
else
return SYS_ARCH_TIMEOUT;
}
sys_mbox_t
sys_mbox_new(int size)
{
sys_mbox_t mbox = ExAllocatePool(NonPagedPool, sizeof(struct _sys_mbox_t));
if (!mbox)
return SYS_MBOX_NULL;
KeInitializeSpinLock(&mbox->Lock);
InitializeListHead(&mbox->ListHead);
KeInitializeEvent(&mbox->Event, NotificationEvent, FALSE);
return mbox;
}
void
sys_mbox_free(sys_mbox_t mbox)
{
ASSERT(IsListEmpty(&mbox->ListHead));
ExFreePool(mbox);
}
void
sys_mbox_post(sys_mbox_t mbox, void *msg)
{
PLWIP_MESSAGE_CONTAINER Container;
KIRQL OldIrql;
Container = ExAllocatePool(NonPagedPool, sizeof(*Container));
ASSERT(Container);
Container->Message = msg;
KeAcquireSpinLock(&mbox->Lock, &OldIrql);
InsertTailList(&mbox->ListHead,
&Container->ListEntry);
KeSetEvent(&mbox->Event, IO_NO_INCREMENT, FALSE);
KeReleaseSpinLock(&mbox->Lock, OldIrql);
}
u32_t
sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
{
LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime;
UINT64 TimeDiff;
NTSTATUS Status;
PVOID Message;
PLWIP_MESSAGE_CONTAINER Container;
PLIST_ENTRY Entry;
KIRQL OldIrql;
PVOID WaitObjects[] = {&mbox->Event, &TerminationEvent};
LargeTimeout.QuadPart = Int32x32To64(timeout, -10000);
KeQuerySystemTime(&PreWaitTime);
Status = KeWaitForMultipleObjects(2,
WaitObjects,
WaitAny,
Executive,
KernelMode,
FALSE,
timeout != 0 ? &LargeTimeout : NULL,
NULL);
if (Status == STATUS_WAIT_0)
{
KeAcquireSpinLock(&mbox->Lock, &OldIrql);
Entry = RemoveHeadList(&mbox->ListHead);
ASSERT(Entry);
if (IsListEmpty(&mbox->ListHead))
KeClearEvent(&mbox->Event);
Container = CONTAINING_RECORD(Entry, LWIP_MESSAGE_CONTAINER, ListEntry);
KeReleaseSpinLock(&mbox->Lock, OldIrql);
KeQuerySystemTime(&PostWaitTime);
TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart;
TimeDiff /= 10000;
Message = Container->Message;
ExFreePool(Container);
if (msg)
*msg = Message;
return TimeDiff;
}
else if (Status == STATUS_WAIT_1)
{
/* DON'T remove ourselves from the thread list! */
PsTerminateSystemThread(STATUS_SUCCESS);
/* We should never get here! */
ASSERT(FALSE);
return 0;
}
else
return SYS_ARCH_TIMEOUT;
}
u32_t
sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
{
if (sys_arch_mbox_fetch(mbox, msg, 1) != SYS_ARCH_TIMEOUT)
return 0;
else
return SYS_MBOX_EMPTY;
}
err_t
sys_mbox_trypost(sys_mbox_t mbox, void *msg)
{
sys_mbox_post(mbox, msg);
return ERR_OK;
}
struct sys_timeouts *sys_arch_timeouts(void)
{
KIRQL OldIrql;
PLIST_ENTRY CurrentEntry;
thread_t Container;
KeAcquireSpinLock(&ThreadListLock, &OldIrql);
CurrentEntry = ThreadListHead.Flink;
while (CurrentEntry != &ThreadListHead)
{
Container = CONTAINING_RECORD(CurrentEntry, struct _thread_t, ListEntry);
if (Container->ThreadId == KeGetCurrentThread())
{
KeReleaseSpinLock(&ThreadListLock, OldIrql);
return &Container->Timeouts;
}
CurrentEntry = CurrentEntry->Flink;
}
KeReleaseSpinLock(&ThreadListLock, OldIrql);
Container = ExAllocatePool(NonPagedPool, sizeof(*Container));
if (!Container)
return SYS_ARCH_NULL;
Container->Name[0] = ANSI_NULL;
Container->ThreadFunction = NULL;
Container->ThreadContext = NULL;
Container->Timeouts.next = NULL;
Container->ThreadId = KeGetCurrentThread();
ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry, &ThreadListLock);
return &Container->Timeouts;
}
VOID
NTAPI
LwipThreadMain(PVOID Context)
{
thread_t Container = Context;
KIRQL OldIrql;
Container->ThreadId = KeGetCurrentThread();
ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry, &ThreadListLock);
Container->ThreadFunction(Container->ThreadContext);
KeAcquireSpinLock(&ThreadListLock, &OldIrql);
RemoveEntryList(&Container->ListEntry);
KeReleaseSpinLock(&ThreadListLock, OldIrql);
ExFreePool(Container);
PsTerminateSystemThread(STATUS_SUCCESS);
}
sys_thread_t
sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
{
thread_t Container;
NTSTATUS Status;
Container = ExAllocatePool(NonPagedPool, strlen(name) + sizeof(*Container));
if (!Container)
return 0;
strcpy(Container->Name, name);
Container->ThreadFunction = thread;
Container->ThreadContext = arg;
Container->Timeouts.next = NULL;
Status = PsCreateSystemThread(&Container->Handle,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
LwipThreadMain,
Container);
if (!NT_SUCCESS(Status))
{
ExFreePool(Container);
return 0;
}
return 0;
}
void
sys_init(void)
{
KeInitializeSpinLock(&ThreadListLock);
InitializeListHead(&ThreadListHead);
KeQuerySystemTime(&StartTime);
KeInitializeEvent(&TerminationEvent, NotificationEvent, FALSE);
}
void
sys_shutdown(void)
{
PLIST_ENTRY CurrentEntry;
thread_t Container;
/* Set the termination event */
KeSetEvent(&TerminationEvent, IO_NO_INCREMENT, FALSE);
/* Loop through the thread list and wait for each to die */
while ((CurrentEntry = ExInterlockedRemoveHeadList(&ThreadListHead, &ThreadListLock)))
{
Container = CONTAINING_RECORD(CurrentEntry, struct _thread_t, ListEntry);
if (Container->ThreadFunction)
{
KeWaitForSingleObject(Container->Handle,
Executive,
KernelMode,
FALSE,
NULL);
ZwClose(Container->Handle);
}
CurrentEntry = CurrentEntry->Flink;
}
}