Use lookaside lists for two most common allocation sizes (mbuf and data buffer)
[reactos.git] / reactos / drivers / lib / ip / transport / tcp / event.c
1 /*
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
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
13 int TCPSocketState(void *ClientData,
14 void *WhichSocket,
15 void *WhichConnection,
16 OSK_UINT NewState ) {
17 PCONNECTION_ENDPOINT Connection = WhichConnection;
18
19 TI_DbgPrint(MID_TRACE,("Flags: %c%c%c%c\n",
20 NewState & SEL_CONNECT ? 'C' : 'c',
21 NewState & SEL_READ ? 'R' : 'r',
22 NewState & SEL_FIN ? 'F' : 'f',
23 NewState & SEL_ACCEPT ? 'A' : 'a'));
24
25 TI_DbgPrint(DEBUG_TCP,("Called: NewState %x (Conn %x) (Change %x)\n",
26 NewState, Connection,
27 Connection ? Connection->State ^ NewState :
28 NewState));
29
30 if( !Connection ) {
31 TI_DbgPrint(DEBUG_TCP,("Socket closing.\n"));
32 Connection = FileFindConnectionByContext( WhichSocket );
33 if( !Connection )
34 return 0;
35 else
36 TI_DbgPrint(DEBUG_TCP,("Found socket %x\n", Connection));
37 }
38
39 TI_DbgPrint(MID_TRACE,("Connection signalled: %d\n",
40 Connection->Signalled));
41
42 Connection->SignalState |= NewState;
43 if( !Connection->Signalled ) {
44 Connection->Signalled = TRUE;
45 InsertTailList( &SignalledConnections, &Connection->SignalList );
46 }
47
48 return 0;
49 }
50
51 void TCPPacketSendComplete( PVOID Context,
52 PNDIS_PACKET NdisPacket,
53 NDIS_STATUS NdisStatus ) {
54 TI_DbgPrint(DEBUG_TCP,("called %x\n", NdisPacket));
55 FreeNdisPacket(NdisPacket);
56 TI_DbgPrint(DEBUG_TCP,("done\n"));
57 }
58
59 #define STRINGIFY(x) #x
60
61 int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) {
62 NDIS_STATUS NdisStatus;
63 PNEIGHBOR_CACHE_ENTRY NCE;
64 IP_PACKET Packet = { 0 };
65 IP_ADDRESS RemoteAddress, LocalAddress;
66 PIPv4_HEADER Header;
67
68 if( *data == 0x45 ) { /* IPv4 */
69 Header = (PIPv4_HEADER)data;
70 LocalAddress.Type = IP_ADDRESS_V4;
71 LocalAddress.Address.IPv4Address = Header->SrcAddr;
72 RemoteAddress.Type = IP_ADDRESS_V4;
73 RemoteAddress.Address.IPv4Address = Header->DstAddr;
74 } else {
75 TI_DbgPrint(MIN_TRACE,("Outgoing packet is not IPv4\n"));
76 OskitDumpBuffer( data, len );
77 return OSK_EINVAL;
78 }
79
80 RemoteAddress.Type = LocalAddress.Type = IP_ADDRESS_V4;
81
82 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
83 TI_DbgPrint(MIN_TRACE,("No route to %s\n", A2S(&RemoteAddress)));
84 return OSK_EADDRNOTAVAIL;
85 }
86
87 NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL,
88 MaxLLHeaderSize + len );
89
90 if (NdisStatus != NDIS_STATUS_SUCCESS) {
91 TI_DbgPrint(DEBUG_TCP, ("Error from NDIS: %08x\n", NdisStatus));
92 return OSK_ENOBUFS;
93 }
94
95 GetDataPtr( Packet.NdisPacket, MaxLLHeaderSize,
96 (PCHAR *)&Packet.Header, &Packet.ContigSize );
97
98 RtlCopyMemory( Packet.Header, data, len );
99
100 Packet.HeaderSize = sizeof(IPv4_HEADER);
101 Packet.TotalSize = len;
102 Packet.SrcAddr = LocalAddress;
103 Packet.DstAddr = RemoteAddress;
104
105 IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL );
106
107 if( !NT_SUCCESS(NdisStatus) ) return OSK_EINVAL;
108 else return 0;
109 }
110
111 int TCPSleep( void *ClientData, void *token, int priority, char *msg,
112 int tmio ) {
113 PSLEEPING_THREAD SleepingThread;
114
115 TI_DbgPrint(DEBUG_TCP,
116 ("Called TSLEEP: tok = %x, pri = %d, wmesg = %s, tmio = %x\n",
117 token, priority, msg, tmio));
118
119 SleepingThread = PoolAllocateBuffer( sizeof( *SleepingThread ) );
120 if( SleepingThread ) {
121 KeInitializeEvent( &SleepingThread->Event, NotificationEvent, FALSE );
122 SleepingThread->SleepToken = token;
123
124 TcpipAcquireFastMutex( &SleepingThreadsLock );
125 InsertTailList( &SleepingThreadsList, &SleepingThread->Entry );
126 TcpipReleaseFastMutex( &SleepingThreadsLock );
127
128 TI_DbgPrint(DEBUG_TCP,("Waiting on %x\n", token));
129 KeWaitForSingleObject( &SleepingThread->Event,
130 WrSuspended,
131 KernelMode,
132 TRUE,
133 NULL );
134
135 TcpipAcquireFastMutex( &SleepingThreadsLock );
136 RemoveEntryList( &SleepingThread->Entry );
137 TcpipReleaseFastMutex( &SleepingThreadsLock );
138
139 PoolFreeBuffer( SleepingThread );
140 }
141 TI_DbgPrint(DEBUG_TCP,("Waiting finished: %x\n", token));
142 return 0;
143 }
144
145 void TCPWakeup( void *ClientData, void *token ) {
146 PLIST_ENTRY Entry;
147 PSLEEPING_THREAD SleepingThread;
148
149 TcpipAcquireFastMutex( &SleepingThreadsLock );
150 Entry = SleepingThreadsList.Flink;
151 while( Entry != &SleepingThreadsList ) {
152 SleepingThread = CONTAINING_RECORD(Entry, SLEEPING_THREAD, Entry);
153 TI_DbgPrint(DEBUG_TCP,("Sleeper @ %x\n", SleepingThread));
154 if( SleepingThread->SleepToken == token ) {
155 TI_DbgPrint(DEBUG_TCP,("Setting event to wake %x\n", token));
156 KeSetEvent( &SleepingThread->Event, IO_NETWORK_INCREMENT, FALSE );
157 }
158 Entry = Entry->Flink;
159 }
160 TcpipReleaseFastMutex( &SleepingThreadsLock );
161 }
162
163 /* Memory management routines
164 *
165 * By far the most requests for memory are either for 128 or 2048 byte blocks,
166 * so we want to satisfy those from lookaside lists. Unfortunately, the
167 * TCPFree() function doesn't pass the size of the block to be freed, so we
168 * need to keep track of it ourselves. We do it by prepending each block with
169 * 4 bytes, indicating if this is a 'L'arge (2048), 'S'mall (128) or 'O'ther
170 * block.
171 */
172
173 /* Set to some non-zero value to get a profile of memory allocation sizes */
174 #define MEM_PROFILE 0
175
176 #define SMALL_SIZE 128
177 #define LARGE_SIZE 2048
178
179 #define SIGNATURE_LARGE TAG('L','L','L','L')
180 #define SIGNATURE_SMALL TAG('S','S','S','S')
181 #define SIGNATURE_OTHER TAG('O','O','O','O')
182 #define TCP_TAG TAG('T','C','P',' ')
183
184 static NPAGED_LOOKASIDE_LIST LargeLookasideList;
185 static NPAGED_LOOKASIDE_LIST SmallLookasideList;
186
187 NTSTATUS
188 TCPMemStartup( void )
189 {
190 ExInitializeNPagedLookasideList( &LargeLookasideList,
191 NULL,
192 NULL,
193 0,
194 LARGE_SIZE + sizeof( ULONG ),
195 TCP_TAG,
196 0 );
197 ExInitializeNPagedLookasideList( &SmallLookasideList,
198 NULL,
199 NULL,
200 0,
201 SMALL_SIZE + sizeof( ULONG ),
202 TCP_TAG,
203 0 );
204
205 return STATUS_SUCCESS;
206 }
207
208 void *TCPMalloc( void *ClientData,
209 OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
210 void *v;
211 ULONG Signature;
212
213 #if 0 != MEM_PROFILE
214 static OSK_UINT *Sizes = NULL, *Counts = NULL, ArrayAllocated = 0;
215 static OSK_UINT ArrayUsed = 0, AllocationCount = 0;
216 OSK_UINT i, NewSize, *NewArray;
217 int Found;
218
219 Found = 0;
220 for ( i = 0; i < ArrayUsed && ! Found; i++ ) {
221 Found = ( Sizes[i] == Bytes );
222 if ( Found ) {
223 Counts[i]++;
224 }
225 }
226 if ( ! Found ) {
227 if ( ArrayAllocated <= ArrayUsed ) {
228 NewSize = ( 0 == ArrayAllocated ? 16 : 2 * ArrayAllocated );
229 NewArray = PoolAllocateBuffer( 2 * NewSize * sizeof( OSK_UINT ) );
230 if ( NULL != NewArray ) {
231 if ( 0 != ArrayAllocated ) {
232 memcpy( NewArray, Sizes,
233 ArrayAllocated * sizeof( OSK_UINT ) );
234 PoolFreeBuffer( Sizes );
235 memcpy( NewArray + NewSize, Counts,
236 ArrayAllocated * sizeof( OSK_UINT ) );
237 PoolFreeBuffer( Counts );
238 }
239 Sizes = NewArray;
240 Counts = NewArray + NewSize;
241 ArrayAllocated = NewSize;
242 } else if ( 0 != ArrayAllocated ) {
243 PoolFreeBuffer( Sizes );
244 PoolFreeBuffer( Counts );
245 ArrayAllocated = 0;
246 }
247 }
248 if ( ArrayUsed < ArrayAllocated ) {
249 Sizes[ArrayUsed] = Bytes;
250 Counts[ArrayUsed] = 1;
251 ArrayUsed++;
252 }
253 }
254
255 if ( 0 == (++AllocationCount % MEM_PROFILE) ) {
256 TI_DbgPrint(DEBUG_TCP, ("Memory allocation size profile:\n"));
257 for ( i = 0; i < ArrayUsed; i++ ) {
258 TI_DbgPrint(DEBUG_TCP,
259 ("Size %4u Count %5u\n", Sizes[i], Counts[i]));
260 }
261 TI_DbgPrint(DEBUG_TCP, ("End of memory allocation size profile\n"));
262 }
263 #endif /* MEM_PROFILE */
264
265 if ( SMALL_SIZE == Bytes ) {
266 v = ExAllocateFromNPagedLookasideList( &SmallLookasideList );
267 Signature = SIGNATURE_SMALL;
268 } else if ( LARGE_SIZE == Bytes ) {
269 v = ExAllocateFromNPagedLookasideList( &LargeLookasideList );
270 Signature = SIGNATURE_LARGE;
271 } else {
272 v = PoolAllocateBuffer( Bytes + sizeof(ULONG) );
273 Signature = SIGNATURE_OTHER;
274 }
275 if( v ) {
276 *((ULONG *) v) = Signature;
277 v = (void *)((char *) v + sizeof(ULONG));
278 TrackWithTag( FOURCC('f','b','s','d'), v, (PCHAR)File, Line );
279 }
280
281 return v;
282 }
283
284 void TCPFree( void *ClientData,
285 void *data, OSK_PCHAR File, OSK_UINT Line ) {
286 ULONG Signature;
287
288 UntrackFL( (PCHAR)File, Line, data );
289 data = (void *)((char *) data - sizeof(ULONG));
290 Signature = *((ULONG *) data);
291 if ( SIGNATURE_SMALL == Signature ) {
292 ExFreeToNPagedLookasideList( &SmallLookasideList, data );
293 } else if ( SIGNATURE_LARGE == Signature ) {
294 ExFreeToNPagedLookasideList( &LargeLookasideList, data );
295 } else if ( SIGNATURE_OTHER == Signature ) {
296 PoolFreeBuffer( data );
297 } else {
298 ASSERT( FALSE );
299 }
300 }
301
302 void
303 TCPMemShutdown( void )
304 {
305 ExDeleteNPagedLookasideList( &SmallLookasideList );
306 ExDeleteNPagedLookasideList( &LargeLookasideList );
307 }