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