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