tabs -> spaces
[reactos.git] / reactos / lib / drivers / 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 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
81 TI_DbgPrint(MIN_TRACE,("No route to %s\n", A2S(&RemoteAddress)));
82 return OSK_EADDRNOTAVAIL;
83 }
84
85 NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL,
86 MaxLLHeaderSize + len );
87
88 if (NdisStatus != NDIS_STATUS_SUCCESS) {
89 TI_DbgPrint(DEBUG_TCP, ("Error from NDIS: %08x\n", NdisStatus));
90 return OSK_ENOBUFS;
91 }
92
93 GetDataPtr( Packet.NdisPacket, MaxLLHeaderSize,
94 (PCHAR *)&Packet.Header, &Packet.ContigSize );
95
96 RtlCopyMemory( Packet.Header, data, len );
97
98 Packet.HeaderSize = sizeof(IPv4_HEADER);
99 Packet.TotalSize = len;
100 Packet.SrcAddr = LocalAddress;
101 Packet.DstAddr = RemoteAddress;
102
103 if (!NT_SUCCESS(IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL )))
104 {
105 FreeNdisPacket(Packet.NdisPacket);
106 return OSK_EINVAL;
107 }
108
109 return 0;
110 }
111
112 int TCPSleep( void *ClientData, void *token, int priority, char *msg,
113 int tmio ) {
114 PSLEEPING_THREAD SleepingThread;
115 LARGE_INTEGER Timeout;
116
117 TI_DbgPrint(DEBUG_TCP,
118 ("Called TSLEEP: tok = %x, pri = %d, wmesg = %s, tmio = %x\n",
119 token, priority, msg, tmio));
120
121 SleepingThread = exAllocatePool( NonPagedPool, sizeof( *SleepingThread ) );
122 if( SleepingThread ) {
123 KeInitializeEvent( &SleepingThread->Event, NotificationEvent, FALSE );
124 SleepingThread->SleepToken = token;
125
126 /* We're going to sleep and need to release the lock, otherwise
127 it's impossible to re-enter oskittcp to deliver the event that's
128 going to wake us */
129 TcpipRecursiveMutexLeave( &TCPLock );
130
131 TcpipAcquireFastMutex( &SleepingThreadsLock );
132 InsertTailList( &SleepingThreadsList, &SleepingThread->Entry );
133 TcpipReleaseFastMutex( &SleepingThreadsLock );
134
135 Timeout.QuadPart = Int32x32To64(tmio, -10000);
136
137 TI_DbgPrint(DEBUG_TCP,("Waiting on %x\n", token));
138 KeWaitForSingleObject( &SleepingThread->Event,
139 Executive,
140 KernelMode,
141 TRUE,
142 (tmio != 0) ? &Timeout : NULL );
143
144 TcpipAcquireFastMutex( &SleepingThreadsLock );
145 RemoveEntryList( &SleepingThread->Entry );
146 TcpipReleaseFastMutex( &SleepingThreadsLock );
147
148 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
149
150 exFreePool( SleepingThread );
151 } else
152 return OSK_ENOBUFS;
153
154 TI_DbgPrint(DEBUG_TCP,("Waiting finished: %x\n", token));
155 return 0;
156 }
157
158 void TCPWakeup( void *ClientData, void *token ) {
159 PLIST_ENTRY Entry;
160 PSLEEPING_THREAD SleepingThread;
161
162 TcpipAcquireFastMutex( &SleepingThreadsLock );
163 Entry = SleepingThreadsList.Flink;
164 while( Entry != &SleepingThreadsList ) {
165 SleepingThread = CONTAINING_RECORD(Entry, SLEEPING_THREAD, Entry);
166 TI_DbgPrint(DEBUG_TCP,("Sleeper @ %x\n", SleepingThread));
167 if( SleepingThread->SleepToken == token ) {
168 TI_DbgPrint(DEBUG_TCP,("Setting event to wake %x\n", token));
169 KeSetEvent( &SleepingThread->Event, IO_NETWORK_INCREMENT, FALSE );
170 }
171 Entry = Entry->Flink;
172 }
173 TcpipReleaseFastMutex( &SleepingThreadsLock );
174 }
175
176 /* Memory management routines
177 *
178 * By far the most requests for memory are either for 128 or 2048 byte blocks,
179 * so we want to satisfy those from lookaside lists. Unfortunately, the
180 * TCPFree() function doesn't pass the size of the block to be freed, so we
181 * need to keep track of it ourselves. We do it by prepending each block with
182 * 4 bytes, indicating if this is a 'L'arge (2048), 'S'mall (128) or 'O'ther
183 * block.
184 */
185
186 /* Set to some non-zero value to get a profile of memory allocation sizes */
187 #define MEM_PROFILE 0
188
189 #define SMALL_SIZE 128
190 #define LARGE_SIZE 2048
191
192 #define SIGNATURE_LARGE TAG('L','L','L','L')
193 #define SIGNATURE_SMALL TAG('S','S','S','S')
194 #define SIGNATURE_OTHER TAG('O','O','O','O')
195 #define TCP_TAG TAG('T','C','P',' ')
196
197 static NPAGED_LOOKASIDE_LIST LargeLookasideList;
198 static NPAGED_LOOKASIDE_LIST SmallLookasideList;
199
200 NTSTATUS
201 TCPMemStartup( void )
202 {
203 ExInitializeNPagedLookasideList( &LargeLookasideList,
204 NULL,
205 NULL,
206 0,
207 LARGE_SIZE + sizeof( ULONG ),
208 TCP_TAG,
209 0 );
210 ExInitializeNPagedLookasideList( &SmallLookasideList,
211 NULL,
212 NULL,
213 0,
214 SMALL_SIZE + sizeof( ULONG ),
215 TCP_TAG,
216 0 );
217
218 return STATUS_SUCCESS;
219 }
220
221 void *TCPMalloc( void *ClientData,
222 OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
223 void *v;
224 ULONG Signature;
225
226 #if 0 != MEM_PROFILE
227 static OSK_UINT *Sizes = NULL, *Counts = NULL, ArrayAllocated = 0;
228 static OSK_UINT ArrayUsed = 0, AllocationCount = 0;
229 OSK_UINT i, NewSize, *NewArray;
230 int Found;
231
232 Found = 0;
233 for ( i = 0; i < ArrayUsed && ! Found; i++ ) {
234 Found = ( Sizes[i] == Bytes );
235 if ( Found ) {
236 Counts[i]++;
237 }
238 }
239 if ( ! Found ) {
240 if ( ArrayAllocated <= ArrayUsed ) {
241 NewSize = ( 0 == ArrayAllocated ? 16 : 2 * ArrayAllocated );
242 NewArray = exAllocatePool( NonPagedPool, 2 * NewSize * sizeof( OSK_UINT ) );
243 if ( NULL != NewArray ) {
244 if ( 0 != ArrayAllocated ) {
245 memcpy( NewArray, Sizes,
246 ArrayAllocated * sizeof( OSK_UINT ) );
247 exFreePool( Sizes );
248 memcpy( NewArray + NewSize, Counts,
249 ArrayAllocated * sizeof( OSK_UINT ) );
250 exFreePool( Counts );
251 }
252 Sizes = NewArray;
253 Counts = NewArray + NewSize;
254 ArrayAllocated = NewSize;
255 } else if ( 0 != ArrayAllocated ) {
256 exFreePool( Sizes );
257 exFreePool( Counts );
258 ArrayAllocated = 0;
259 }
260 }
261 if ( ArrayUsed < ArrayAllocated ) {
262 Sizes[ArrayUsed] = Bytes;
263 Counts[ArrayUsed] = 1;
264 ArrayUsed++;
265 }
266 }
267
268 if ( 0 == (++AllocationCount % MEM_PROFILE) ) {
269 TI_DbgPrint(DEBUG_TCP, ("Memory allocation size profile:\n"));
270 for ( i = 0; i < ArrayUsed; i++ ) {
271 TI_DbgPrint(DEBUG_TCP,
272 ("Size %4u Count %5u\n", Sizes[i], Counts[i]));
273 }
274 TI_DbgPrint(DEBUG_TCP, ("End of memory allocation size profile\n"));
275 }
276 #endif /* MEM_PROFILE */
277
278 if ( SMALL_SIZE == Bytes ) {
279 v = ExAllocateFromNPagedLookasideList( &SmallLookasideList );
280 Signature = SIGNATURE_SMALL;
281 } else if ( LARGE_SIZE == Bytes ) {
282 v = ExAllocateFromNPagedLookasideList( &LargeLookasideList );
283 Signature = SIGNATURE_LARGE;
284 } else {
285 v = ExAllocatePool( NonPagedPool, Bytes + sizeof(ULONG) );
286 Signature = SIGNATURE_OTHER;
287 }
288 if( v ) {
289 *((ULONG *) v) = Signature;
290 v = (void *)((char *) v + sizeof(ULONG));
291 TrackWithTag( FOURCC('f','b','s','d'), v, (PCHAR)File, Line );
292 }
293
294 return v;
295 }
296
297 void TCPFree( void *ClientData,
298 void *data, OSK_PCHAR File, OSK_UINT Line ) {
299 ULONG Signature;
300
301 UntrackFL( (PCHAR)File, Line, data, FOURCC('f','b','s','d') );
302 data = (void *)((char *) data - sizeof(ULONG));
303 Signature = *((ULONG *) data);
304 if ( SIGNATURE_SMALL == Signature ) {
305 ExFreeToNPagedLookasideList( &SmallLookasideList, data );
306 } else if ( SIGNATURE_LARGE == Signature ) {
307 ExFreeToNPagedLookasideList( &LargeLookasideList, data );
308 } else if ( SIGNATURE_OTHER == Signature ) {
309 ExFreePool( data );
310 } else {
311 ASSERT( FALSE );
312 }
313 }
314
315 void
316 TCPMemShutdown( void )
317 {
318 ExDeleteNPagedLookasideList( &SmallLookasideList );
319 ExDeleteNPagedLookasideList( &LargeLookasideList );
320 }