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