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