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