- Remove ALL the unneeded "author date id revision" svn properties.
[reactos.git] / reactos / drivers / network / afd / afd / listen.c
1 /* $Id: listen.c 57233 2012-09-04 03:01:15Z cgutman $
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/listen.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
7 * UPDATE HISTORY:
8 * 20040708 Created
9 */
10 #include "afd.h"
11
12 static NTSTATUS SatisfyAccept( PAFD_DEVICE_EXTENSION DeviceExt,
13 PIRP Irp,
14 PFILE_OBJECT NewFileObject,
15 PAFD_TDI_OBJECT_QELT Qelt ) {
16 PAFD_FCB FCB = NewFileObject->FsContext;
17 NTSTATUS Status;
18
19 if( !SocketAcquireStateLock( FCB ) )
20 return LostSocket( Irp );
21
22 /* Transfer the connection to the new socket, launch the opening read */
23 AFD_DbgPrint(MID_TRACE,("Completing a real accept (FCB %x)\n", FCB));
24
25 FCB->Connection = Qelt->Object;
26
27 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
28 FCB->RemoteAddress =
29 TaCopyTransportAddress( Qelt->ConnInfo->RemoteAddress );
30
31 if( !FCB->RemoteAddress )
32 Status = STATUS_NO_MEMORY;
33 else
34 Status = MakeSocketIntoConnection( FCB );
35
36 if (NT_SUCCESS(Status))
37 Status = TdiBuildConnectionInfo(&FCB->ConnectCallInfo, FCB->RemoteAddress);
38
39 if (NT_SUCCESS(Status))
40 Status = TdiBuildConnectionInfo(&FCB->ConnectReturnInfo, FCB->RemoteAddress);
41
42 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
43 }
44
45 static NTSTATUS SatisfyPreAccept( PIRP Irp, PAFD_TDI_OBJECT_QELT Qelt ) {
46 PAFD_RECEIVED_ACCEPT_DATA ListenReceive =
47 (PAFD_RECEIVED_ACCEPT_DATA)Irp->AssociatedIrp.SystemBuffer;
48 PTA_IP_ADDRESS IPAddr;
49
50 ListenReceive->SequenceNumber = Qelt->Seq;
51
52 AFD_DbgPrint(MID_TRACE,("Giving SEQ %d to userland\n", Qelt->Seq));
53 AFD_DbgPrint(MID_TRACE,("Socket Address (K) %x (U) %x\n",
54 &ListenReceive->Address,
55 Qelt->ConnInfo->RemoteAddress));
56
57 TaCopyTransportAddressInPlace( &ListenReceive->Address,
58 Qelt->ConnInfo->RemoteAddress );
59
60 IPAddr = (PTA_IP_ADDRESS)&ListenReceive->Address;
61
62 AFD_DbgPrint(MID_TRACE,("IPAddr->TAAddressCount %d\n",
63 IPAddr->TAAddressCount));
64 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].AddressType %d\n",
65 IPAddr->Address[0].AddressType));
66 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].AddressLength %d\n",
67 IPAddr->Address[0].AddressLength));
68 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].Address[0].sin_port %x\n",
69 IPAddr->Address[0].Address[0].sin_port));
70 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].Address[0].sin_addr %x\n",
71 IPAddr->Address[0].Address[0].in_addr));
72
73 if( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
74
75 Irp->IoStatus.Information = ((PCHAR)&IPAddr[1]) - ((PCHAR)ListenReceive);
76 Irp->IoStatus.Status = STATUS_SUCCESS;
77 (void)IoSetCancelRoutine(Irp, NULL);
78 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
79 return STATUS_SUCCESS;
80 }
81
82 static NTSTATUS NTAPI ListenComplete( PDEVICE_OBJECT DeviceObject,
83 PIRP Irp,
84 PVOID Context ) {
85 NTSTATUS Status = STATUS_SUCCESS;
86 PAFD_FCB FCB = (PAFD_FCB)Context;
87 PAFD_TDI_OBJECT_QELT Qelt;
88 PLIST_ENTRY NextIrpEntry;
89 PIRP NextIrp;
90
91 if( !SocketAcquireStateLock( FCB ) )
92 return STATUS_FILE_CLOSED;
93
94 ASSERT(FCB->ListenIrp.InFlightRequest == Irp);
95 FCB->ListenIrp.InFlightRequest = NULL;
96
97 if( FCB->State == SOCKET_STATE_CLOSED ) {
98 /* Cleanup our IRP queue because the FCB is being destroyed */
99 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_PREACCEPT] ) ) {
100 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_PREACCEPT]);
101 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
102 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
103 NextIrp->IoStatus.Information = 0;
104 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
105 (void)IoSetCancelRoutine(NextIrp, NULL);
106 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
107 }
108
109 /* Free ConnectionReturnInfo and ConnectionCallInfo */
110 if (FCB->ListenIrp.ConnectionReturnInfo)
111 {
112 ExFreePool(FCB->ListenIrp.ConnectionReturnInfo);
113 FCB->ListenIrp.ConnectionReturnInfo = NULL;
114 }
115
116 if (FCB->ListenIrp.ConnectionCallInfo)
117 {
118 ExFreePool(FCB->ListenIrp.ConnectionCallInfo);
119 FCB->ListenIrp.ConnectionCallInfo = NULL;
120 }
121
122 SocketStateUnlock( FCB );
123 return STATUS_FILE_CLOSED;
124 }
125
126 AFD_DbgPrint(MID_TRACE,("Completing listen request.\n"));
127 AFD_DbgPrint(MID_TRACE,("IoStatus was %x\n", Irp->IoStatus.Status));
128
129 if (Irp->IoStatus.Status != STATUS_SUCCESS)
130 {
131 SocketStateUnlock(FCB);
132 return Irp->IoStatus.Status;
133 }
134
135 Qelt = ExAllocatePool( NonPagedPool, sizeof(*Qelt) );
136 if( !Qelt ) {
137 Status = STATUS_NO_MEMORY;
138 } else {
139 UINT AddressType =
140 FCB->LocalAddress->Address[0].AddressType;
141
142 Qelt->Object = FCB->Connection;
143 Qelt->Seq = FCB->ConnSeq++;
144 AFD_DbgPrint(MID_TRACE,("Address Type: %d (RA %x)\n",
145 AddressType,
146 FCB->ListenIrp.
147 ConnectionReturnInfo->RemoteAddress));
148
149 Status = TdiBuildNullConnectionInfo( &Qelt->ConnInfo, AddressType );
150 if( NT_SUCCESS(Status) ) {
151 TaCopyTransportAddressInPlace
152 ( Qelt->ConnInfo->RemoteAddress,
153 FCB->ListenIrp.ConnectionReturnInfo->RemoteAddress );
154 InsertTailList( &FCB->PendingConnections, &Qelt->ListEntry );
155 }
156 }
157
158 /* Satisfy a pre-accept request if one is available */
159 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_PREACCEPT] ) &&
160 !IsListEmpty( &FCB->PendingConnections ) ) {
161 PLIST_ENTRY PendingIrp =
162 RemoveHeadList( &FCB->PendingIrpList[FUNCTION_PREACCEPT] );
163 PLIST_ENTRY PendingConn = FCB->PendingConnections.Flink;
164 SatisfyPreAccept
165 ( CONTAINING_RECORD( PendingIrp, IRP,
166 Tail.Overlay.ListEntry ),
167 CONTAINING_RECORD( PendingConn, AFD_TDI_OBJECT_QELT,
168 ListEntry ) );
169 }
170
171 /* Launch new accept socket */
172 Status = WarmSocketForConnection( FCB );
173
174 if (NT_SUCCESS(Status))
175 {
176 Status = TdiBuildNullConnectionInfoInPlace(FCB->ListenIrp.ConnectionCallInfo,
177 FCB->LocalAddress->Address[0].AddressType);
178 ASSERT(Status == STATUS_SUCCESS);
179
180 Status = TdiBuildNullConnectionInfoInPlace(FCB->ListenIrp.ConnectionReturnInfo,
181 FCB->LocalAddress->Address[0].AddressType);
182 ASSERT(Status == STATUS_SUCCESS);
183
184 Status = TdiListen( &FCB->ListenIrp.InFlightRequest,
185 FCB->Connection.Object,
186 &FCB->ListenIrp.ConnectionCallInfo,
187 &FCB->ListenIrp.ConnectionReturnInfo,
188 &FCB->ListenIrp.Iosb,
189 ListenComplete,
190 FCB );
191
192 if (Status == STATUS_PENDING)
193 Status = STATUS_SUCCESS;
194 }
195
196 /* Trigger a select return if appropriate */
197 if( !IsListEmpty( &FCB->PendingConnections ) ) {
198 FCB->PollState |= AFD_EVENT_ACCEPT;
199 FCB->PollStatus[FD_ACCEPT_BIT] = STATUS_SUCCESS;
200 PollReeval( FCB->DeviceExt, FCB->FileObject );
201 } else
202 FCB->PollState &= ~AFD_EVENT_ACCEPT;
203
204 SocketStateUnlock( FCB );
205
206 return Status;
207 }
208
209 NTSTATUS AfdListenSocket( PDEVICE_OBJECT DeviceObject, PIRP Irp,
210 PIO_STACK_LOCATION IrpSp ) {
211 NTSTATUS Status = STATUS_SUCCESS;
212 PFILE_OBJECT FileObject = IrpSp->FileObject;
213 PAFD_FCB FCB = FileObject->FsContext;
214 PAFD_LISTEN_DATA ListenReq;
215
216 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
217
218 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
219
220 if( !(ListenReq = LockRequest( Irp, IrpSp, FALSE, NULL )) )
221 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
222 0 );
223
224 if( FCB->State != SOCKET_STATE_BOUND ) {
225 Status = STATUS_INVALID_PARAMETER;
226 AFD_DbgPrint(MIN_TRACE,("Could not listen an unbound socket\n"));
227 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
228 }
229
230 FCB->DelayedAccept = ListenReq->UseDelayedAcceptance;
231
232 AFD_DbgPrint(MID_TRACE,("ADDRESSFILE: %x\n", FCB->AddressFile.Handle));
233
234 Status = WarmSocketForConnection( FCB );
235
236 AFD_DbgPrint(MID_TRACE,("Status from warmsocket %x\n", Status));
237
238 if( !NT_SUCCESS(Status) ) return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
239
240 Status = TdiBuildNullConnectionInfo
241 ( &FCB->ListenIrp.ConnectionCallInfo,
242 FCB->LocalAddress->Address[0].AddressType );
243
244 if (!NT_SUCCESS(Status)) return UnlockAndMaybeComplete(FCB, Status, Irp, 0);
245
246 Status = TdiBuildNullConnectionInfo
247 ( &FCB->ListenIrp.ConnectionReturnInfo,
248 FCB->LocalAddress->Address[0].AddressType );
249
250 if (!NT_SUCCESS(Status))
251 {
252 ExFreePool(FCB->ListenIrp.ConnectionCallInfo);
253 FCB->ListenIrp.ConnectionCallInfo = NULL;
254 return UnlockAndMaybeComplete(FCB, Status, Irp, 0);
255 }
256
257 FCB->State = SOCKET_STATE_LISTENING;
258
259 Status = TdiListen( &FCB->ListenIrp.InFlightRequest,
260 FCB->Connection.Object,
261 &FCB->ListenIrp.ConnectionCallInfo,
262 &FCB->ListenIrp.ConnectionReturnInfo,
263 &FCB->ListenIrp.Iosb,
264 ListenComplete,
265 FCB );
266
267 if( Status == STATUS_PENDING )
268 Status = STATUS_SUCCESS;
269
270 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
271 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
272 }
273
274 NTSTATUS AfdWaitForListen( PDEVICE_OBJECT DeviceObject, PIRP Irp,
275 PIO_STACK_LOCATION IrpSp ) {
276 PFILE_OBJECT FileObject = IrpSp->FileObject;
277 PAFD_FCB FCB = FileObject->FsContext;
278 NTSTATUS Status;
279
280 AFD_DbgPrint(MID_TRACE,("Called\n"));
281
282 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
283
284 if( !IsListEmpty( &FCB->PendingConnections ) ) {
285 PLIST_ENTRY PendingConn = FCB->PendingConnections.Flink;
286
287 /* We have a pending connection ... complete this irp right away */
288 Status = SatisfyPreAccept
289 ( Irp,
290 CONTAINING_RECORD
291 ( PendingConn, AFD_TDI_OBJECT_QELT, ListEntry ) );
292
293 AFD_DbgPrint(MID_TRACE,("Completed a wait for accept\n"));
294
295 if ( !IsListEmpty( &FCB->PendingConnections ) )
296 {
297 FCB->PollState |= AFD_EVENT_ACCEPT;
298 FCB->PollStatus[FD_ACCEPT_BIT] = STATUS_SUCCESS;
299 PollReeval( FCB->DeviceExt, FCB->FileObject );
300 } else
301 FCB->PollState &= ~AFD_EVENT_ACCEPT;
302
303 SocketStateUnlock( FCB );
304 return Status;
305 } else if (FCB->NonBlocking) {
306 AFD_DbgPrint(MIN_TRACE,("No connection ready on a non-blocking socket\n"));
307
308 return UnlockAndMaybeComplete(FCB, STATUS_CANT_WAIT, Irp, 0);
309 } else {
310 AFD_DbgPrint(MID_TRACE,("Holding\n"));
311
312 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_PREACCEPT );
313 }
314 }
315
316 NTSTATUS AfdAccept( PDEVICE_OBJECT DeviceObject, PIRP Irp,
317 PIO_STACK_LOCATION IrpSp ) {
318 NTSTATUS Status = STATUS_SUCCESS;
319 PFILE_OBJECT FileObject = IrpSp->FileObject;
320 PAFD_DEVICE_EXTENSION DeviceExt =
321 (PAFD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
322 PAFD_FCB FCB = FileObject->FsContext;
323 PAFD_ACCEPT_DATA AcceptData = Irp->AssociatedIrp.SystemBuffer;
324 PLIST_ENTRY PendingConn;
325
326 AFD_DbgPrint(MID_TRACE,("Called\n"));
327
328 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
329
330 FCB->EventSelectDisabled &= ~AFD_EVENT_ACCEPT;
331
332 for( PendingConn = FCB->PendingConnections.Flink;
333 PendingConn != &FCB->PendingConnections;
334 PendingConn = PendingConn->Flink ) {
335 PAFD_TDI_OBJECT_QELT PendingConnObj =
336 CONTAINING_RECORD( PendingConn, AFD_TDI_OBJECT_QELT, ListEntry );
337
338 AFD_DbgPrint(MID_TRACE,("Comparing Seq %d to Q %d\n",
339 AcceptData->SequenceNumber,
340 PendingConnObj->Seq));
341
342 if( PendingConnObj->Seq == AcceptData->SequenceNumber ) {
343 PFILE_OBJECT NewFileObject = NULL;
344
345 RemoveEntryList( PendingConn );
346
347 Status = ObReferenceObjectByHandle
348 ( AcceptData->ListenHandle,
349 FILE_ALL_ACCESS,
350 NULL,
351 KernelMode,
352 (PVOID *)&NewFileObject,
353 NULL );
354
355 if( !NT_SUCCESS(Status) ) return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
356
357 ASSERT(NewFileObject != FileObject);
358 ASSERT(NewFileObject->FsContext != FCB);
359
360 /* We have a pending connection ... complete this irp right away */
361 Status = SatisfyAccept( DeviceExt, Irp, NewFileObject, PendingConnObj );
362
363 ObDereferenceObject( NewFileObject );
364
365 AFD_DbgPrint(MID_TRACE,("Completed a wait for accept\n"));
366
367 ExFreePool( PendingConnObj );
368
369 if( !IsListEmpty( &FCB->PendingConnections ) )
370 {
371 FCB->PollState |= AFD_EVENT_ACCEPT;
372 FCB->PollStatus[FD_ACCEPT_BIT] = STATUS_SUCCESS;
373 PollReeval( FCB->DeviceExt, FCB->FileObject );
374 } else
375 FCB->PollState &= ~AFD_EVENT_ACCEPT;
376
377 SocketStateUnlock( FCB );
378 return Status;
379 }
380 }
381
382 AFD_DbgPrint(MIN_TRACE,("No connection waiting\n"));
383
384 return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL, Irp, 0 );
385 }