- Defined __NTDRIVER__ to turn on some code that is meant only for kernel mode.
[reactos.git] / reactos / drivers / lib / 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 extern ULONG TCP_IPIdentification;
14 extern LIST_ENTRY SleepingThreadsList;
15 extern FAST_MUTEX SleepingThreadsLock;
16 extern RECURSIVE_MUTEX TCPLock;
17
18 int TCPSocketState(void *ClientData,
19 void *WhichSocket,
20 void *WhichConnection,
21 OSK_UINT NewState ) {
22 NTSTATUS Status = STATUS_SUCCESS;
23 PCONNECTION_ENDPOINT Connection = WhichConnection;
24 PTCP_COMPLETION_ROUTINE Complete;
25 PTDI_BUCKET Bucket;
26 PLIST_ENTRY Entry;
27
28 TI_DbgPrint(MID_TRACE,("Called: NewState %x (Conn %x) (Change %x)\n",
29 NewState, Connection,
30 Connection ? Connection->State ^ NewState :
31 NewState));
32
33 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
34
35 if( !Connection ) {
36 TI_DbgPrint(MID_TRACE,("Socket closing.\n"));
37 Connection = FileFindConnectionByContext( WhichSocket );
38 if( !Connection ) {
39 TcpipRecursiveMutexLeave( &TCPLock );
40 return 0;
41 } else
42 TI_DbgPrint(MID_TRACE,("Found socket %x\n", Connection));
43 }
44
45 if( ((NewState & SEL_CONNECT) || (NewState & SEL_FIN)) &&
46 !(Connection->State & (SEL_CONNECT | SEL_FIN)) ) {
47 while( !IsListEmpty( &Connection->ConnectRequest ) ) {
48 Connection->State |= NewState & (SEL_CONNECT | SEL_FIN);
49 Entry = RemoveHeadList( &Connection->ConnectRequest );
50 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
51 Complete = Bucket->Request.RequestNotifyObject;
52 TI_DbgPrint(MID_TRACE,
53 ("Completing Connect Request %x\n", Bucket->Request));
54 if( NewState & SEL_FIN ) Status = STATUS_CONNECTION_REFUSED;
55 TcpipRecursiveMutexLeave( &TCPLock );
56 Complete( Bucket->Request.RequestContext, Status, 0 );
57 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
58 /* Frees the bucket allocated in TCPConnect */
59 PoolFreeBuffer( Bucket );
60 }
61 }
62 if( (NewState & SEL_READ) || (NewState & SEL_FIN) ) {
63 TI_DbgPrint(MID_TRACE,("Readable (or closed): irp list %s\n",
64 IsListEmpty(&Connection->ReceiveRequest) ?
65 "empty" : "nonempty"));
66
67 while( !IsListEmpty( &Connection->ReceiveRequest ) ) {
68 PIRP Irp;
69 OSK_UINT RecvLen = 0, Received = 0;
70 OSK_PCHAR RecvBuffer = 0;
71 PMDL Mdl;
72 NTSTATUS Status;
73
74 Entry = RemoveHeadList( &Connection->ReceiveRequest );
75 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
76 Complete = Bucket->Request.RequestNotifyObject;
77
78 TI_DbgPrint(MID_TRACE,
79 ("Readable, Completing read request %x\n",
80 Bucket->Request));
81
82 Irp = Bucket->Request.RequestContext;
83 Mdl = Irp->MdlAddress;
84
85 TI_DbgPrint(MID_TRACE,
86 ("Getting the user buffer from %x\n", Mdl));
87
88 NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
89
90 TI_DbgPrint(MID_TRACE,
91 ("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
92
93 if( (NewState & SEL_FIN) && !RecvLen ) {
94 TI_DbgPrint(MID_TRACE, ("EOF From socket\n"));
95 Status = STATUS_END_OF_FILE;
96 Received = 0;
97 } else {
98 TI_DbgPrint(MID_TRACE, ("Connection: %x\n", Connection));
99 TI_DbgPrint
100 (MID_TRACE,
101 ("Connection->SocketContext: %x\n",
102 Connection->SocketContext));
103 TI_DbgPrint(MID_TRACE, ("RecvBuffer: %x\n", RecvBuffer));
104
105 Status = TCPTranslateError
106 ( OskitTCPRecv( Connection->SocketContext,
107 RecvBuffer,
108 RecvLen,
109 &Received,
110 0 ) );
111 }
112
113 TI_DbgPrint(MID_TRACE,("TCP Bytes: %d\n", Received));
114
115 if( Status == STATUS_SUCCESS && Received != 0 ) {
116 TI_DbgPrint(MID_TRACE,("Received %d bytes with status %x\n",
117 Received, Status));
118
119 TI_DbgPrint(MID_TRACE,
120 ("Completing Receive Request: %x\n",
121 Bucket->Request));
122
123 TcpipRecursiveMutexLeave( &TCPLock );
124 Complete( Bucket->Request.RequestContext,
125 STATUS_SUCCESS, Received );
126 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
127 } else if( Status == STATUS_PENDING ||
128 (Status == STATUS_SUCCESS && Received == 0) ) {
129 InsertHeadList( &Connection->ReceiveRequest,
130 &Bucket->Entry );
131 break;
132 } else {
133 TI_DbgPrint(MID_TRACE,
134 ("Completing Receive request: %x %x\n",
135 Bucket->Request, Status));
136 TcpipRecursiveMutexLeave( &TCPLock );
137 Complete( Bucket->Request.RequestContext, Status, 0 );
138 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
139 }
140 }
141 }
142
143 TcpipRecursiveMutexLeave( &TCPLock );
144
145 return 0;
146 }
147
148 void TCPPacketSendComplete( PVOID Context,
149 PNDIS_PACKET NdisPacket,
150 NDIS_STATUS NdisStatus ) {
151 TI_DbgPrint(MID_TRACE,("called %x\n", NdisPacket));
152 FreeNdisPacket(NdisPacket);
153 TI_DbgPrint(MID_TRACE,("done\n"));
154 }
155
156 #define STRINGIFY(x) #x
157
158 int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) {
159 NDIS_STATUS NdisStatus;
160 PNEIGHBOR_CACHE_ENTRY NCE;
161 IP_PACKET Packet = { 0 };
162 IP_ADDRESS RemoteAddress, LocalAddress;
163 PIPv4_HEADER Header;
164
165 if( *data == 0x45 ) { /* IPv4 */
166 Header = (PIPv4_HEADER)data;
167 LocalAddress.Type = IP_ADDRESS_V4;
168 LocalAddress.Address.IPv4Address = Header->SrcAddr;
169 RemoteAddress.Type = IP_ADDRESS_V4;
170 RemoteAddress.Address.IPv4Address = Header->DstAddr;
171 } else {
172 DbgPrint("Don't currently handle IPv6\n");
173 KeBugCheck(4);
174 }
175
176 RemoteAddress.Type = LocalAddress.Type = IP_ADDRESS_V4;
177
178 DbgPrint("OSKIT SENDING PACKET *** %x -> %x\n",
179 LocalAddress.Address.IPv4Address,
180 RemoteAddress.Address.IPv4Address);
181
182 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress )))
183 return OSK_EADDRNOTAVAIL;
184
185 NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL,
186 MaxLLHeaderSize + len );
187
188 if (NdisStatus != NDIS_STATUS_SUCCESS) {
189 TI_DbgPrint(MAX_TRACE, ("Error from NDIS: %08x\n", NdisStatus));
190 return STATUS_NO_MEMORY;
191 }
192
193 GetDataPtr( Packet.NdisPacket, MaxLLHeaderSize,
194 (PCHAR *)&Packet.Header, &Packet.ContigSize );
195
196 RtlCopyMemory( Packet.Header, data, len );
197
198 Packet.HeaderSize = sizeof(IPv4_HEADER);
199 Packet.TotalSize = len;
200 Packet.SrcAddr = LocalAddress;
201 Packet.DstAddr = RemoteAddress;
202
203 IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL );
204
205 if( !NT_SUCCESS(NdisStatus) ) return OSK_EINVAL;
206 else return 0;
207 }
208
209 void *TCPMalloc( void *ClientData,
210 OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
211 void *v = PoolAllocateBuffer( Bytes );
212 if( v ) TrackWithTag( FOURCC('f','b','s','d'), v, File, Line );
213 return v;
214 }
215
216 void TCPFree( void *ClientData,
217 void *data, OSK_PCHAR File, OSK_UINT Line ) {
218 UntrackFL( File, Line, data );
219 PoolFreeBuffer( data );
220 }
221
222 int TCPSleep( void *ClientData, void *token, int priority, char *msg,
223 int tmio ) {
224 PSLEEPING_THREAD SleepingThread;
225
226 TI_DbgPrint(MID_TRACE,
227 ("Called TSLEEP: tok = %x, pri = %d, wmesg = %s, tmio = %x\n",
228 token, priority, msg, tmio));
229
230 SleepingThread = PoolAllocateBuffer( sizeof( *SleepingThread ) );
231 if( SleepingThread ) {
232 KeInitializeEvent( &SleepingThread->Event, NotificationEvent, FALSE );
233 SleepingThread->SleepToken = token;
234
235 TcpipAcquireFastMutex( &SleepingThreadsLock );
236 InsertTailList( &SleepingThreadsList, &SleepingThread->Entry );
237 TcpipReleaseFastMutex( &SleepingThreadsLock );
238
239 TI_DbgPrint(MID_TRACE,("Waiting on %x\n", token));
240 KeWaitForSingleObject( &SleepingThread->Event,
241 WrSuspended,
242 KernelMode,
243 TRUE,
244 NULL );
245
246 TcpipAcquireFastMutex( &SleepingThreadsLock );
247 RemoveEntryList( &SleepingThread->Entry );
248 TcpipReleaseFastMutex( &SleepingThreadsLock );
249
250 PoolFreeBuffer( SleepingThread );
251 }
252 TI_DbgPrint(MID_TRACE,("Waiting finished: %x\n", token));
253 return 0;
254 }
255
256 void TCPWakeup( void *ClientData, void *token ) {
257 PLIST_ENTRY Entry;
258 PSLEEPING_THREAD SleepingThread;
259
260 TcpipAcquireFastMutex( &SleepingThreadsLock );
261 Entry = SleepingThreadsList.Flink;
262 while( Entry != &SleepingThreadsList ) {
263 SleepingThread = CONTAINING_RECORD(Entry, SLEEPING_THREAD, Entry);
264 TI_DbgPrint(MID_TRACE,("Sleeper @ %x\n", SleepingThread));
265 if( SleepingThread->SleepToken == token ) {
266 TI_DbgPrint(MID_TRACE,("Setting event to wake %x\n", token));
267 KeSetEvent( &SleepingThread->Event, IO_NETWORK_INCREMENT, FALSE );
268 }
269 Entry = Entry->Flink;
270 }
271 TcpipReleaseFastMutex( &SleepingThreadsLock );
272 }