#include "precomp.h"
-extern ULONG TCP_IPIdentification;
-extern LIST_ENTRY SleepingThreadsList;
-extern FAST_MUTEX SleepingThreadsLock;
-
int TCPSocketState(void *ClientData,
- void *WhichSocket,
+ void *WhichSocket,
void *WhichConnection,
OSK_UINT NewState ) {
PCONNECTION_ENDPOINT Connection = WhichConnection;
- PTCP_COMPLETION_ROUTINE Complete;
- PTDI_BUCKET Bucket;
- PLIST_ENTRY Entry;
- TI_DbgPrint(MID_TRACE,("Called: NewState %x (Conn %x)\n",
- NewState, Connection));
+ TI_DbgPrint(MID_TRACE,("Flags: %c%c%c%c\n",
+ NewState & SEL_CONNECT ? 'C' : 'c',
+ NewState & SEL_READ ? 'R' : 'r',
+ NewState & SEL_FIN ? 'F' : 'f',
+ NewState & SEL_ACCEPT ? 'A' : 'a'));
+
+ TI_DbgPrint(DEBUG_TCP,("Called: NewState %x (Conn %x) (Change %x)\n",
+ NewState, Connection,
+ Connection ? Connection->State ^ NewState :
+ NewState));
if( !Connection ) {
- TI_DbgPrint(MID_TRACE,("Socket closing.\n"));
- return 0;
+ TI_DbgPrint(DEBUG_TCP,("Socket closing.\n"));
+ Connection = FileFindConnectionByContext( WhichSocket );
+ if( !Connection )
+ return 0;
+ else
+ TI_DbgPrint(DEBUG_TCP,("Found socket %x\n", Connection));
}
- if( (NewState & SEL_CONNECT) &&
- !(Connection->State & SEL_CONNECT) ) {
- while( !IsListEmpty( &Connection->ConnectRequest ) ) {
- Connection->State |= SEL_CONNECT;
- Entry = RemoveHeadList( &Connection->ConnectRequest );
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete = Bucket->Request.RequestNotifyObject;
- TI_DbgPrint(MID_TRACE,
- ("Completing Connect Request %x\n", Bucket->Request));
- Complete( Bucket->Request.RequestContext, STATUS_SUCCESS, 0 );
- /* Frees the bucket allocated in TCPConnect */
- PoolFreeBuffer( Bucket );
- }
- } else if( (NewState & SEL_READ) || (NewState & SEL_FIN) ) {
- TI_DbgPrint(MID_TRACE,("Readable (or closed): irp list %s\n",
- IsListEmpty(&Connection->ReceiveRequest) ?
- "empty" : "nonempty"));
-
- while( !IsListEmpty( &Connection->ReceiveRequest ) ) {
- PIRP Irp;
- OSK_UINT RecvLen = 0, Received = 0;
- OSK_PCHAR RecvBuffer = 0;
- PMDL Mdl;
- NTSTATUS Status;
-
- Entry = RemoveHeadList( &Connection->ReceiveRequest );
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete = Bucket->Request.RequestNotifyObject;
-
- TI_DbgPrint(MID_TRACE,
- ("Readable, Completing read request %x\n",
- Bucket->Request));
-
- Irp = Bucket->Request.RequestContext;
- Mdl = Irp->MdlAddress;
-
- TI_DbgPrint(MID_TRACE,
- ("Getting the user buffer from %x\n", Mdl));
-
- NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
-
- TI_DbgPrint(MID_TRACE,
- ("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
-
- if( NewState & SEL_FIN && !RecvLen ) {
- Status = STATUS_END_OF_FILE;
- Received = 0;
- } else {
- TI_DbgPrint(MID_TRACE, ("Connection: %x\n", Connection));
- TI_DbgPrint
- (MID_TRACE,
- ("Connection->SocketContext: %x\n",
- Connection->SocketContext));
- TI_DbgPrint(MID_TRACE, ("RecvBuffer: %x\n", RecvBuffer));
-
- Status = TCPTranslateError
- ( OskitTCPRecv( Connection->SocketContext,
- RecvBuffer,
- RecvLen,
- &Received,
- 0 ) );
- }
+ TI_DbgPrint(MID_TRACE,("Connection signalled: %d\n",
+ Connection->Signalled));
- TI_DbgPrint(MID_TRACE,("TCP Bytes: %d\n", Received));
-
- if( Status == STATUS_SUCCESS && Received != 0 ) {
- TI_DbgPrint(MID_TRACE,("Received %d bytes with status %x\n",
- Received, Status));
-
- TI_DbgPrint(MID_TRACE,
- ("Completing Receive Request: %x\n",
- Bucket->Request));
-
- Complete( Bucket->Request.RequestContext,
- STATUS_SUCCESS, Received );
- } else if( Status == STATUS_PENDING ||
- (Status == STATUS_SUCCESS && Received == 0) ) {
- InsertHeadList( &Connection->ReceiveRequest,
- &Bucket->Entry );
- break;
- } else {
- TI_DbgPrint(MID_TRACE,
- ("Completing Receive request: %x %x\n",
- Bucket->Request, Status));
- Complete( Bucket->Request.RequestContext, Status, 0 );
- }
- }
- }
+ Connection->SignalState |= NewState;
+ if( !Connection->Signalled ) {
+ Connection->Signalled = TRUE;
+ InsertTailList( &SignalledConnections, &Connection->SignalList );
+ }
return 0;
}
void TCPPacketSendComplete( PVOID Context,
PNDIS_PACKET NdisPacket,
NDIS_STATUS NdisStatus ) {
- TI_DbgPrint(MID_TRACE,("called %x\n", NdisPacket));
+ TI_DbgPrint(DEBUG_TCP,("called %x\n", NdisPacket));
FreeNdisPacket(NdisPacket);
- TI_DbgPrint(MID_TRACE,("done\n"));
+ TI_DbgPrint(DEBUG_TCP,("done\n"));
}
#define STRINGIFY(x) #x
int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) {
- NTSTATUS Status;
NDIS_STATUS NdisStatus;
- ROUTE_CACHE_NODE *RCN;
+ PNEIGHBOR_CACHE_ENTRY NCE;
IP_PACKET Packet = { 0 };
IP_ADDRESS RemoteAddress, LocalAddress;
PIPv4_HEADER Header;
- TI_DbgPrint(MID_TRACE,("TCP OUTPUT (%x:%d):\n", data, len));
- OskitDumpBuffer( data, len );
-
if( *data == 0x45 ) { /* IPv4 */
Header = (PIPv4_HEADER)data;
LocalAddress.Type = IP_ADDRESS_V4;
RemoteAddress.Type = IP_ADDRESS_V4;
RemoteAddress.Address.IPv4Address = Header->DstAddr;
} else {
- DbgPrint("Don't currently handle IPv6\n");
- KeBugCheck(4);
+ TI_DbgPrint(MIN_TRACE,("Outgoing packet is not IPv4\n"));
+ OskitDumpBuffer( data, len );
+ return OSK_EINVAL;
}
RemoteAddress.Type = LocalAddress.Type = IP_ADDRESS_V4;
- DbgPrint("OSKIT SENDING PACKET *** %x -> %x\n",
- LocalAddress.Address.IPv4Address,
- RemoteAddress.Address.IPv4Address);
-
- Status = RouteGetRouteToDestination( &RemoteAddress, NULL, &RCN );
-
- if( !NT_SUCCESS(Status) || !RCN ) return OSK_EADDRNOTAVAIL;
+ if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
+ TI_DbgPrint(MIN_TRACE,("No route to %s\n", A2S(&RemoteAddress)));
+ return OSK_EADDRNOTAVAIL;
+ }
- NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL,
+ NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL,
MaxLLHeaderSize + len );
-
+
if (NdisStatus != NDIS_STATUS_SUCCESS) {
- TI_DbgPrint(MAX_TRACE, ("Error from NDIS: %08x\n", NdisStatus));
- return STATUS_NO_MEMORY;
+ TI_DbgPrint(DEBUG_TCP, ("Error from NDIS: %08x\n", NdisStatus));
+ return OSK_ENOBUFS;
}
- GetDataPtr( Packet.NdisPacket, MaxLLHeaderSize,
+ GetDataPtr( Packet.NdisPacket, MaxLLHeaderSize,
(PCHAR *)&Packet.Header, &Packet.ContigSize );
RtlCopyMemory( Packet.Header, data, len );
Packet.SrcAddr = LocalAddress;
Packet.DstAddr = RemoteAddress;
- IPSendDatagram( &Packet, RCN, TCPPacketSendComplete, NULL );
+ IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL );
if( !NT_SUCCESS(NdisStatus) ) return OSK_EINVAL;
else return 0;
}
-void *TCPMalloc( void *ClientData,
- OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
- void *v = PoolAllocateBuffer( Bytes );
- if( v ) TrackWithTag( FOURCC('f','b','s','d'), v, File, Line );
- return v;
-}
-
-void TCPFree( void *ClientData,
- void *data, OSK_PCHAR File, OSK_UINT Line ) {
- UntrackFL( File, Line, data );
- PoolFreeBuffer( data );
-}
-
int TCPSleep( void *ClientData, void *token, int priority, char *msg,
int tmio ) {
PSLEEPING_THREAD SleepingThread;
-
- TI_DbgPrint(MID_TRACE,
+
+ TI_DbgPrint(DEBUG_TCP,
("Called TSLEEP: tok = %x, pri = %d, wmesg = %s, tmio = %x\n",
token, priority, msg, tmio));
InsertTailList( &SleepingThreadsList, &SleepingThread->Entry );
TcpipReleaseFastMutex( &SleepingThreadsLock );
- TI_DbgPrint(MID_TRACE,("Waiting on %x\n", token));
+ TI_DbgPrint(DEBUG_TCP,("Waiting on %x\n", token));
KeWaitForSingleObject( &SleepingThread->Event,
WrSuspended,
KernelMode,
PoolFreeBuffer( SleepingThread );
}
- TI_DbgPrint(MID_TRACE,("Waiting finished: %x\n", token));
+ TI_DbgPrint(DEBUG_TCP,("Waiting finished: %x\n", token));
return 0;
}
Entry = SleepingThreadsList.Flink;
while( Entry != &SleepingThreadsList ) {
SleepingThread = CONTAINING_RECORD(Entry, SLEEPING_THREAD, Entry);
- TI_DbgPrint(MID_TRACE,("Sleeper @ %x\n", SleepingThread));
+ TI_DbgPrint(DEBUG_TCP,("Sleeper @ %x\n", SleepingThread));
if( SleepingThread->SleepToken == token ) {
- TI_DbgPrint(MID_TRACE,("Setting event to wake %x\n", token));
+ TI_DbgPrint(DEBUG_TCP,("Setting event to wake %x\n", token));
KeSetEvent( &SleepingThread->Event, IO_NETWORK_INCREMENT, FALSE );
}
Entry = Entry->Flink;
}
TcpipReleaseFastMutex( &SleepingThreadsLock );
}
+
+/* Memory management routines
+ *
+ * By far the most requests for memory are either for 128 or 2048 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 (2048), '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 2048
+
+#define SIGNATURE_LARGE TAG('L','L','L','L')
+#define SIGNATURE_SMALL TAG('S','S','S','S')
+#define SIGNATURE_OTHER TAG('O','O','O','O')
+#define TCP_TAG TAG('T','C','P',' ')
+
+static NPAGED_LOOKASIDE_LIST LargeLookasideList;
+static NPAGED_LOOKASIDE_LIST SmallLookasideList;
+
+NTSTATUS
+TCPMemStartup( void )
+{
+ ExInitializeNPagedLookasideList( &LargeLookasideList,
+ NULL,
+ NULL,
+ 0,
+ LARGE_SIZE + sizeof( ULONG ),
+ TCP_TAG,
+ 0 );
+ ExInitializeNPagedLookasideList( &SmallLookasideList,
+ NULL,
+ NULL,
+ 0,
+ SMALL_SIZE + sizeof( ULONG ),
+ TCP_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 = PoolAllocateBuffer( 2 * NewSize * sizeof( OSK_UINT ) );
+ if ( NULL != NewArray ) {
+ if ( 0 != ArrayAllocated ) {
+ memcpy( NewArray, Sizes,
+ ArrayAllocated * sizeof( OSK_UINT ) );
+ PoolFreeBuffer( Sizes );
+ memcpy( NewArray + NewSize, Counts,
+ ArrayAllocated * sizeof( OSK_UINT ) );
+ PoolFreeBuffer( Counts );
+ }
+ Sizes = NewArray;
+ Counts = NewArray + NewSize;
+ ArrayAllocated = NewSize;
+ } else if ( 0 != ArrayAllocated ) {
+ PoolFreeBuffer( Sizes );
+ PoolFreeBuffer( 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++ ) {
+ TI_DbgPrint(DEBUG_TCP,
+ ("Size %4u Count %5u\n", Sizes[i], Counts[i]));
+ }
+ TI_DbgPrint(DEBUG_TCP, ("End of memory allocation size profile\n"));
+ }
+#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 = PoolAllocateBuffer( Bytes + sizeof(ULONG) );
+ Signature = SIGNATURE_OTHER;
+ }
+ if( v ) {
+ *((ULONG *) v) = Signature;
+ v = (void *)((char *) v + sizeof(ULONG));
+ TrackWithTag( FOURCC('f','b','s','d'), v, (PCHAR)File, Line );
+ }
+
+ return v;
+}
+
+void TCPFree( void *ClientData,
+ void *data, OSK_PCHAR File, OSK_UINT Line ) {
+ ULONG Signature;
+
+ UntrackFL( (PCHAR)File, Line, data );
+ 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 ) {
+ PoolFreeBuffer( data );
+ } else {
+ ASSERT( FALSE );
+ }
+}
+
+void
+TCPMemShutdown( void )
+{
+ ExDeleteNPagedLookasideList( &SmallLookasideList );
+ ExDeleteNPagedLookasideList( &LargeLookasideList );
+}