2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/tcp/event.c
5 * PURPOSE: Transmission Control Protocol -- Events from oskittcp
6 * PROGRAMMERS: Art Yerkes
8 * CSH 01/08-2000 Created
13 int TCPSocketState(void *ClientData
,
15 void *WhichConnection
,
17 PCONNECTION_ENDPOINT Connection
= WhichConnection
;
19 ASSERT_LOCKED(&TCPLock
);
21 TI_DbgPrint(MID_TRACE
,("Flags: %c%c%c%c\n",
22 NewState
& SEL_CONNECT
? 'C' : 'c',
23 NewState
& SEL_READ
? 'R' : 'r',
24 NewState
& SEL_FIN
? 'F' : 'f',
25 NewState
& SEL_ACCEPT
? 'A' : 'a'));
27 TI_DbgPrint(DEBUG_TCP
,("Called: NewState %x (Conn %x) (Change %x)\n",
29 Connection
? Connection
->State
^ NewState
:
33 TI_DbgPrint(DEBUG_TCP
,("Socket closing.\n"));
34 Connection
= FileFindConnectionByContext( WhichSocket
);
38 TI_DbgPrint(DEBUG_TCP
,("Found socket %x\n", Connection
));
41 TI_DbgPrint(MID_TRACE
,("Connection signalled: %d\n",
42 Connection
->Signalled
));
44 Connection
->SignalState
|= NewState
;
45 if( !Connection
->Signalled
) {
46 Connection
->Signalled
= TRUE
;
47 ExInterlockedInsertTailList( &SignalledConnectionsList
, &Connection
->SignalList
, &SignalledConnectionsLock
);
53 void TCPPacketSendComplete( PVOID Context
,
54 PNDIS_PACKET NdisPacket
,
55 NDIS_STATUS NdisStatus
) {
56 TI_DbgPrint(DEBUG_TCP
,("called %x\n", NdisPacket
));
57 FreeNdisPacket(NdisPacket
);
58 TI_DbgPrint(DEBUG_TCP
,("done\n"));
61 #define STRINGIFY(x) #x
63 int TCPPacketSend(void *ClientData
, OSK_PCHAR data
, OSK_UINT len
) {
64 NDIS_STATUS NdisStatus
;
65 PNEIGHBOR_CACHE_ENTRY NCE
;
66 IP_PACKET Packet
= { 0 };
67 IP_ADDRESS RemoteAddress
, LocalAddress
;
70 ASSERT_LOCKED(&TCPLock
);
72 if( *data
== 0x45 ) { /* IPv4 */
73 Header
= (PIPv4_HEADER
)data
;
74 LocalAddress
.Type
= IP_ADDRESS_V4
;
75 LocalAddress
.Address
.IPv4Address
= Header
->SrcAddr
;
76 RemoteAddress
.Type
= IP_ADDRESS_V4
;
77 RemoteAddress
.Address
.IPv4Address
= Header
->DstAddr
;
79 TI_DbgPrint(MIN_TRACE
,("Outgoing packet is not IPv4\n"));
80 OskitDumpBuffer( data
, len
);
84 if(!(NCE
= RouteGetRouteToDestination( &RemoteAddress
))) {
85 TI_DbgPrint(MIN_TRACE
,("No route to %s\n", A2S(&RemoteAddress
)));
86 return OSK_EADDRNOTAVAIL
;
89 NdisStatus
= AllocatePacketWithBuffer( &Packet
.NdisPacket
, NULL
, len
);
91 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
92 TI_DbgPrint(DEBUG_TCP
, ("Error from NDIS: %08x\n", NdisStatus
));
96 GetDataPtr( Packet
.NdisPacket
, 0,
97 (PCHAR
*)&Packet
.Header
, &Packet
.ContigSize
);
99 RtlCopyMemory( Packet
.Header
, data
, len
);
101 Packet
.HeaderSize
= sizeof(IPv4_HEADER
);
102 Packet
.TotalSize
= len
;
103 Packet
.SrcAddr
= LocalAddress
;
104 Packet
.DstAddr
= RemoteAddress
;
106 if (!NT_SUCCESS(IPSendDatagram( &Packet
, NCE
, TCPPacketSendComplete
, NULL
)))
108 FreeNdisPacket(Packet
.NdisPacket
);
115 int TCPSleep( void *ClientData
, void *token
, int priority
, char *msg
,
117 PSLEEPING_THREAD SleepingThread
;
118 LARGE_INTEGER Timeout
;
120 ASSERT_LOCKED(&TCPLock
);
122 TI_DbgPrint(DEBUG_TCP
,
123 ("Called TSLEEP: tok = %x, pri = %d, wmesg = %s, tmio = %x\n",
124 token
, priority
, msg
, tmio
));
126 SleepingThread
= exAllocatePool( NonPagedPool
, sizeof( *SleepingThread
) );
127 if( SleepingThread
) {
128 KeInitializeEvent( &SleepingThread
->Event
, NotificationEvent
, FALSE
);
129 SleepingThread
->SleepToken
= token
;
131 /* We're going to sleep and need to release the lock, otherwise
132 it's impossible to re-enter oskittcp to deliver the event that's
134 TcpipRecursiveMutexLeave( &TCPLock
);
136 TcpipAcquireFastMutex( &SleepingThreadsLock
);
137 InsertTailList( &SleepingThreadsList
, &SleepingThread
->Entry
);
138 TcpipReleaseFastMutex( &SleepingThreadsLock
);
140 Timeout
.QuadPart
= Int32x32To64(tmio
, -10000);
142 TI_DbgPrint(DEBUG_TCP
,("Waiting on %x\n", token
));
143 KeWaitForSingleObject( &SleepingThread
->Event
,
147 (tmio
!= 0) ? &Timeout
: NULL
);
149 TcpipAcquireFastMutex( &SleepingThreadsLock
);
150 RemoveEntryList( &SleepingThread
->Entry
);
151 TcpipReleaseFastMutex( &SleepingThreadsLock
);
153 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
155 exFreePool( SleepingThread
);
159 TI_DbgPrint(DEBUG_TCP
,("Waiting finished: %x\n", token
));
163 void TCPWakeup( void *ClientData
, void *token
) {
165 PSLEEPING_THREAD SleepingThread
;
167 ASSERT_LOCKED(&TCPLock
);
169 TcpipAcquireFastMutex( &SleepingThreadsLock
);
170 Entry
= SleepingThreadsList
.Flink
;
171 while( Entry
!= &SleepingThreadsList
) {
172 SleepingThread
= CONTAINING_RECORD(Entry
, SLEEPING_THREAD
, Entry
);
173 TI_DbgPrint(DEBUG_TCP
,("Sleeper @ %x\n", SleepingThread
));
174 if( SleepingThread
->SleepToken
== token
) {
175 TI_DbgPrint(DEBUG_TCP
,("Setting event to wake %x\n", token
));
176 KeSetEvent( &SleepingThread
->Event
, IO_NETWORK_INCREMENT
, FALSE
);
178 Entry
= Entry
->Flink
;
180 TcpipReleaseFastMutex( &SleepingThreadsLock
);
183 /* Memory management routines
185 * By far the most requests for memory are either for 128 or 2048 byte blocks,
186 * so we want to satisfy those from lookaside lists. Unfortunately, the
187 * TCPFree() function doesn't pass the size of the block to be freed, so we
188 * need to keep track of it ourselves. We do it by prepending each block with
189 * 4 bytes, indicating if this is a 'L'arge (2048), 'S'mall (128) or 'O'ther
193 /* Set to some non-zero value to get a profile of memory allocation sizes */
194 #define MEM_PROFILE 0
196 #define SMALL_SIZE 128
197 #define LARGE_SIZE 2048
199 #define SIGNATURE_LARGE 'LLLL'
200 #define SIGNATURE_SMALL 'SSSS'
201 #define SIGNATURE_OTHER 'OOOO'
202 #define TCP_TAG ' PCT'
204 static NPAGED_LOOKASIDE_LIST LargeLookasideList
;
205 static NPAGED_LOOKASIDE_LIST SmallLookasideList
;
208 TCPMemStartup( void )
210 ExInitializeNPagedLookasideList( &LargeLookasideList
,
214 LARGE_SIZE
+ sizeof( ULONG
),
217 ExInitializeNPagedLookasideList( &SmallLookasideList
,
221 SMALL_SIZE
+ sizeof( ULONG
),
225 return STATUS_SUCCESS
;
228 void *TCPMalloc( void *ClientData
,
229 OSK_UINT Bytes
, OSK_PCHAR File
, OSK_UINT Line
) {
233 ASSERT_LOCKED(&TCPLock
);
236 static OSK_UINT
*Sizes
= NULL
, *Counts
= NULL
, ArrayAllocated
= 0;
237 static OSK_UINT ArrayUsed
= 0, AllocationCount
= 0;
238 OSK_UINT i
, NewSize
, *NewArray
;
242 for ( i
= 0; i
< ArrayUsed
&& ! Found
; i
++ ) {
243 Found
= ( Sizes
[i
] == Bytes
);
249 if ( ArrayAllocated
<= ArrayUsed
) {
250 NewSize
= ( 0 == ArrayAllocated
? 16 : 2 * ArrayAllocated
);
251 NewArray
= exAllocatePool( NonPagedPool
, 2 * NewSize
* sizeof( OSK_UINT
) );
252 if ( NULL
!= NewArray
) {
253 if ( 0 != ArrayAllocated
) {
254 memcpy( NewArray
, Sizes
,
255 ArrayAllocated
* sizeof( OSK_UINT
) );
257 memcpy( NewArray
+ NewSize
, Counts
,
258 ArrayAllocated
* sizeof( OSK_UINT
) );
259 exFreePool( Counts
);
262 Counts
= NewArray
+ NewSize
;
263 ArrayAllocated
= NewSize
;
264 } else if ( 0 != ArrayAllocated
) {
266 exFreePool( Counts
);
270 if ( ArrayUsed
< ArrayAllocated
) {
271 Sizes
[ArrayUsed
] = Bytes
;
272 Counts
[ArrayUsed
] = 1;
277 if ( 0 == (++AllocationCount
% MEM_PROFILE
) ) {
278 TI_DbgPrint(DEBUG_TCP
, ("Memory allocation size profile:\n"));
279 for ( i
= 0; i
< ArrayUsed
; i
++ ) {
280 TI_DbgPrint(DEBUG_TCP
,
281 ("Size %4u Count %5u\n", Sizes
[i
], Counts
[i
]));
283 TI_DbgPrint(DEBUG_TCP
, ("End of memory allocation size profile\n"));
285 #endif /* MEM_PROFILE */
287 if ( SMALL_SIZE
== Bytes
) {
288 v
= ExAllocateFromNPagedLookasideList( &SmallLookasideList
);
289 Signature
= SIGNATURE_SMALL
;
290 } else if ( LARGE_SIZE
== Bytes
) {
291 v
= ExAllocateFromNPagedLookasideList( &LargeLookasideList
);
292 Signature
= SIGNATURE_LARGE
;
294 v
= ExAllocatePool( NonPagedPool
, Bytes
+ sizeof(ULONG
) );
295 Signature
= SIGNATURE_OTHER
;
298 *((ULONG
*) v
) = Signature
;
299 v
= (void *)((char *) v
+ sizeof(ULONG
));
300 TrackWithTag( FOURCC('f','b','s','d'), v
, (PCHAR
)File
, Line
);
306 void TCPFree( void *ClientData
,
307 void *data
, OSK_PCHAR File
, OSK_UINT Line
) {
310 ASSERT_LOCKED(&TCPLock
);
312 UntrackFL( (PCHAR
)File
, Line
, data
, FOURCC('f','b','s','d') );
313 data
= (void *)((char *) data
- sizeof(ULONG
));
314 Signature
= *((ULONG
*) data
);
315 if ( SIGNATURE_SMALL
== Signature
) {
316 ExFreeToNPagedLookasideList( &SmallLookasideList
, data
);
317 } else if ( SIGNATURE_LARGE
== Signature
) {
318 ExFreeToNPagedLookasideList( &LargeLookasideList
, data
);
319 } else if ( SIGNATURE_OTHER
== Signature
) {
327 TCPMemShutdown( void )
329 ExDeleteNPagedLookasideList( &SmallLookasideList
);
330 ExDeleteNPagedLookasideList( &LargeLookasideList
);