- Stop using the TCPLock to protect all entries into the IP lib
[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 ULONG OldState;
19 KIRQL OldIrql;
20
21 ASSERT_LOCKED(&TCPLock);
22
23 TI_DbgPrint(MID_TRACE,("Flags: %c%c%c%c\n",
24 NewState & SEL_CONNECT ? 'C' : 'c',
25 NewState & SEL_READ ? 'R' : 'r',
26 NewState & SEL_FIN ? 'F' : 'f',
27 NewState & SEL_ACCEPT ? 'A' : 'a'));
28
29 TI_DbgPrint(DEBUG_TCP,("Called: NewState %x (Conn %x) (Change %x)\n",
30 NewState, Connection,
31 Connection ? Connection->SignalState ^ NewState :
32 NewState));
33
34 if( !Connection ) {
35 TI_DbgPrint(DEBUG_TCP,("Socket closing.\n"));
36 Connection = FileFindConnectionByContext( WhichSocket );
37 if( !Connection )
38 return 0;
39 else
40 TI_DbgPrint(DEBUG_TCP,("Found socket %x\n", Connection));
41 }
42
43 OldState = Connection->SignalState;
44
45 Connection->SignalState |= NewState;
46
47 TcpipRecursiveMutexLeave(&TCPLock);
48
49 /* We must not be locked when handling signalled connections
50 * because a completion could trigger another IOCTL which
51 * would cause a deadlock
52 */
53 NewState = HandleSignalledConnection(Connection);
54
55 TcpipRecursiveMutexEnter(&TCPLock);
56
57 KeAcquireSpinLock(&SignalledConnectionsLock, &OldIrql);
58 if ((NewState == 0 || NewState == SEL_FIN) &&
59 (OldState != 0 && OldState != SEL_FIN))
60 {
61 RemoveEntryList(&Connection->SignalList);
62 }
63 else if (NewState != 0 && NewState != SEL_FIN)
64 {
65 InsertTailList(&SignalledConnectionsList, &Connection->SignalList);
66 }
67 KeReleaseSpinLock(&SignalledConnectionsLock, OldIrql);
68
69 return 0;
70 }
71
72 void TCPPacketSendComplete( PVOID Context,
73 PNDIS_PACKET NdisPacket,
74 NDIS_STATUS NdisStatus ) {
75 TI_DbgPrint(DEBUG_TCP,("called %x\n", NdisPacket));
76 FreeNdisPacket(NdisPacket);
77 TI_DbgPrint(DEBUG_TCP,("done\n"));
78 }
79
80 #define STRINGIFY(x) #x
81
82 int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) {
83 NDIS_STATUS NdisStatus;
84 PNEIGHBOR_CACHE_ENTRY NCE;
85 IP_PACKET Packet = { 0 };
86 IP_ADDRESS RemoteAddress, LocalAddress;
87 PIPv4_HEADER Header;
88
89 ASSERT_LOCKED(&TCPLock);
90
91 if( *data == 0x45 ) { /* IPv4 */
92 Header = (PIPv4_HEADER)data;
93 LocalAddress.Type = IP_ADDRESS_V4;
94 LocalAddress.Address.IPv4Address = Header->SrcAddr;
95 RemoteAddress.Type = IP_ADDRESS_V4;
96 RemoteAddress.Address.IPv4Address = Header->DstAddr;
97 } else {
98 TI_DbgPrint(MIN_TRACE,("Outgoing packet is not IPv4\n"));
99 OskitDumpBuffer( data, len );
100 return OSK_EINVAL;
101 }
102
103 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
104 TI_DbgPrint(MIN_TRACE,("No route to %s\n", A2S(&RemoteAddress)));
105 return OSK_EADDRNOTAVAIL;
106 }
107
108 NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL, len );
109
110 if (NdisStatus != NDIS_STATUS_SUCCESS) {
111 TI_DbgPrint(DEBUG_TCP, ("Error from NDIS: %08x\n", NdisStatus));
112 return OSK_ENOBUFS;
113 }
114
115 GetDataPtr( Packet.NdisPacket, 0,
116 (PCHAR *)&Packet.Header, &Packet.ContigSize );
117
118 RtlCopyMemory( Packet.Header, data, len );
119
120 Packet.HeaderSize = sizeof(IPv4_HEADER);
121 Packet.TotalSize = len;
122 Packet.SrcAddr = LocalAddress;
123 Packet.DstAddr = RemoteAddress;
124
125 if (!NT_SUCCESS(IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL )))
126 {
127 FreeNdisPacket(Packet.NdisPacket);
128 return OSK_EINVAL;
129 }
130
131 return 0;
132 }
133
134 /* Memory management routines
135 *
136 * By far the most requests for memory are either for 128 or 2048 byte blocks,
137 * so we want to satisfy those from lookaside lists. Unfortunately, the
138 * TCPFree() function doesn't pass the size of the block to be freed, so we
139 * need to keep track of it ourselves. We do it by prepending each block with
140 * 4 bytes, indicating if this is a 'L'arge (2048), 'S'mall (128) or 'O'ther
141 * block.
142 */
143
144 /* Set to some non-zero value to get a profile of memory allocation sizes */
145 #define MEM_PROFILE 0
146
147 #define SMALL_SIZE 128
148 #define LARGE_SIZE 2048
149
150 #define SIGNATURE_LARGE 'LLLL'
151 #define SIGNATURE_SMALL 'SSSS'
152 #define SIGNATURE_OTHER 'OOOO'
153 #define TCP_TAG ' PCT'
154
155 static NPAGED_LOOKASIDE_LIST LargeLookasideList;
156 static NPAGED_LOOKASIDE_LIST SmallLookasideList;
157
158 NTSTATUS
159 TCPMemStartup( void )
160 {
161 ExInitializeNPagedLookasideList( &LargeLookasideList,
162 NULL,
163 NULL,
164 0,
165 LARGE_SIZE + sizeof( ULONG ),
166 TCP_TAG,
167 0 );
168 ExInitializeNPagedLookasideList( &SmallLookasideList,
169 NULL,
170 NULL,
171 0,
172 SMALL_SIZE + sizeof( ULONG ),
173 TCP_TAG,
174 0 );
175
176 return STATUS_SUCCESS;
177 }
178
179 void *TCPMalloc( void *ClientData,
180 OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
181 void *v;
182 ULONG Signature;
183
184 ASSERT_LOCKED(&TCPLock);
185
186 #if 0 != MEM_PROFILE
187 static OSK_UINT *Sizes = NULL, *Counts = NULL, ArrayAllocated = 0;
188 static OSK_UINT ArrayUsed = 0, AllocationCount = 0;
189 OSK_UINT i, NewSize, *NewArray;
190 int Found;
191
192 Found = 0;
193 for ( i = 0; i < ArrayUsed && ! Found; i++ ) {
194 Found = ( Sizes[i] == Bytes );
195 if ( Found ) {
196 Counts[i]++;
197 }
198 }
199 if ( ! Found ) {
200 if ( ArrayAllocated <= ArrayUsed ) {
201 NewSize = ( 0 == ArrayAllocated ? 16 : 2 * ArrayAllocated );
202 NewArray = exAllocatePool( NonPagedPool, 2 * NewSize * sizeof( OSK_UINT ) );
203 if ( NULL != NewArray ) {
204 if ( 0 != ArrayAllocated ) {
205 memcpy( NewArray, Sizes,
206 ArrayAllocated * sizeof( OSK_UINT ) );
207 exFreePool( Sizes );
208 memcpy( NewArray + NewSize, Counts,
209 ArrayAllocated * sizeof( OSK_UINT ) );
210 exFreePool( Counts );
211 }
212 Sizes = NewArray;
213 Counts = NewArray + NewSize;
214 ArrayAllocated = NewSize;
215 } else if ( 0 != ArrayAllocated ) {
216 exFreePool( Sizes );
217 exFreePool( Counts );
218 ArrayAllocated = 0;
219 }
220 }
221 if ( ArrayUsed < ArrayAllocated ) {
222 Sizes[ArrayUsed] = Bytes;
223 Counts[ArrayUsed] = 1;
224 ArrayUsed++;
225 }
226 }
227
228 if ( 0 == (++AllocationCount % MEM_PROFILE) ) {
229 TI_DbgPrint(DEBUG_TCP, ("Memory allocation size profile:\n"));
230 for ( i = 0; i < ArrayUsed; i++ ) {
231 TI_DbgPrint(DEBUG_TCP,
232 ("Size %4u Count %5u\n", Sizes[i], Counts[i]));
233 }
234 TI_DbgPrint(DEBUG_TCP, ("End of memory allocation size profile\n"));
235 }
236 #endif /* MEM_PROFILE */
237
238 if ( SMALL_SIZE == Bytes ) {
239 v = ExAllocateFromNPagedLookasideList( &SmallLookasideList );
240 Signature = SIGNATURE_SMALL;
241 } else if ( LARGE_SIZE == Bytes ) {
242 v = ExAllocateFromNPagedLookasideList( &LargeLookasideList );
243 Signature = SIGNATURE_LARGE;
244 } else {
245 v = ExAllocatePool( NonPagedPool, Bytes + sizeof(ULONG) );
246 Signature = SIGNATURE_OTHER;
247 }
248 if( v ) {
249 *((ULONG *) v) = Signature;
250 v = (void *)((char *) v + sizeof(ULONG));
251 TrackWithTag( FOURCC('f','b','s','d'), v, (PCHAR)File, Line );
252 }
253
254 return v;
255 }
256
257 void TCPFree( void *ClientData,
258 void *data, OSK_PCHAR File, OSK_UINT Line ) {
259 ULONG Signature;
260
261 ASSERT_LOCKED(&TCPLock);
262
263 UntrackFL( (PCHAR)File, Line, data, FOURCC('f','b','s','d') );
264 data = (void *)((char *) data - sizeof(ULONG));
265 Signature = *((ULONG *) data);
266 if ( SIGNATURE_SMALL == Signature ) {
267 ExFreeToNPagedLookasideList( &SmallLookasideList, data );
268 } else if ( SIGNATURE_LARGE == Signature ) {
269 ExFreeToNPagedLookasideList( &LargeLookasideList, data );
270 } else if ( SIGNATURE_OTHER == Signature ) {
271 ExFreePool( data );
272 } else {
273 ASSERT( FALSE );
274 }
275 }
276
277 void
278 TCPMemShutdown( void )
279 {
280 ExDeleteNPagedLookasideList( &SmallLookasideList );
281 ExDeleteNPagedLookasideList( &LargeLookasideList );
282 }