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