2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/connect.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
15 AfdGetConnectOptions(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
16 PIO_STACK_LOCATION IrpSp
)
18 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
19 PAFD_FCB FCB
= FileObject
->FsContext
;
20 UINT BufferSize
= IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
22 UNREFERENCED_PARAMETER(DeviceObject
);
24 if (!SocketAcquireStateLock(FCB
)) return LostSocket(Irp
);
26 if (FCB
->ConnectOptionsSize
== 0)
28 AFD_DbgPrint(MIN_TRACE
,("Invalid parameter\n"));
29 return UnlockAndMaybeComplete(FCB
, STATUS_INVALID_PARAMETER
, Irp
, 0);
32 ASSERT(FCB
->ConnectOptions
);
34 if (FCB
->FilledConnectOptions
< BufferSize
) BufferSize
= FCB
->FilledConnectOptions
;
36 RtlCopyMemory(Irp
->UserBuffer
,
40 return UnlockAndMaybeComplete(FCB
, STATUS_SUCCESS
, Irp
, BufferSize
);
45 AfdSetConnectOptions(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
46 PIO_STACK_LOCATION IrpSp
)
48 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
49 PAFD_FCB FCB
= FileObject
->FsContext
;
50 PVOID ConnectOptions
= LockRequest(Irp
, IrpSp
, FALSE
, NULL
);
51 UINT ConnectOptionsSize
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
53 UNREFERENCED_PARAMETER(DeviceObject
);
55 if (!SocketAcquireStateLock(FCB
)) return LostSocket(Irp
);
58 return UnlockAndMaybeComplete(FCB
, STATUS_NO_MEMORY
, Irp
, 0);
60 if (FCB
->ConnectOptions
)
62 ExFreePool(FCB
->ConnectOptions
);
63 FCB
->ConnectOptions
= NULL
;
64 FCB
->ConnectOptionsSize
= 0;
65 FCB
->FilledConnectOptions
= 0;
68 FCB
->ConnectOptions
= ExAllocatePool(PagedPool
, ConnectOptionsSize
);
69 if (!FCB
->ConnectOptions
)
70 return UnlockAndMaybeComplete(FCB
, STATUS_NO_MEMORY
, Irp
, 0);
72 RtlCopyMemory(FCB
->ConnectOptions
,
76 FCB
->ConnectOptionsSize
= ConnectOptionsSize
;
78 return UnlockAndMaybeComplete(FCB
, STATUS_SUCCESS
, Irp
, 0);
83 AfdSetConnectOptionsSize(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
84 PIO_STACK_LOCATION IrpSp
)
86 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
87 PAFD_FCB FCB
= FileObject
->FsContext
;
88 PUINT ConnectOptionsSize
= LockRequest(Irp
, IrpSp
, FALSE
, NULL
);
89 UINT BufferSize
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
91 UNREFERENCED_PARAMETER(DeviceObject
);
93 if (!SocketAcquireStateLock(FCB
)) return LostSocket(Irp
);
95 if (!ConnectOptionsSize
)
96 return UnlockAndMaybeComplete(FCB
, STATUS_NO_MEMORY
, Irp
, 0);
98 if (BufferSize
< sizeof(UINT
))
100 AFD_DbgPrint(MIN_TRACE
,("Buffer too small\n"));
101 return UnlockAndMaybeComplete(FCB
, STATUS_BUFFER_TOO_SMALL
, Irp
, 0);
104 if (FCB
->ConnectOptions
)
106 ExFreePool(FCB
->ConnectOptions
);
107 FCB
->ConnectOptionsSize
= 0;
108 FCB
->FilledConnectOptions
= 0;
111 FCB
->ConnectOptions
= ExAllocatePool(PagedPool
, *ConnectOptionsSize
);
112 if (!FCB
->ConnectOptions
) return UnlockAndMaybeComplete(FCB
, STATUS_NO_MEMORY
, Irp
, 0);
114 FCB
->ConnectOptionsSize
= *ConnectOptionsSize
;
116 return UnlockAndMaybeComplete(FCB
, STATUS_SUCCESS
, Irp
, 0);
121 AfdGetConnectData(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
122 PIO_STACK_LOCATION IrpSp
)
124 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
125 PAFD_FCB FCB
= FileObject
->FsContext
;
126 UINT BufferSize
= IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
128 UNREFERENCED_PARAMETER(DeviceObject
);
130 if (!SocketAcquireStateLock(FCB
)) return LostSocket(Irp
);
132 if (FCB
->ConnectDataSize
== 0)
134 AFD_DbgPrint(MIN_TRACE
,("Invalid parameter\n"));
135 return UnlockAndMaybeComplete(FCB
, STATUS_INVALID_PARAMETER
, Irp
, 0);
138 ASSERT(FCB
->ConnectData
);
140 if (FCB
->FilledConnectData
< BufferSize
) BufferSize
= FCB
->FilledConnectData
;
142 RtlCopyMemory(Irp
->UserBuffer
,
146 return UnlockAndMaybeComplete(FCB
, STATUS_SUCCESS
, Irp
, BufferSize
);
151 AfdSetConnectData(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
152 PIO_STACK_LOCATION IrpSp
)
154 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
155 PAFD_FCB FCB
= FileObject
->FsContext
;
156 PVOID ConnectData
= LockRequest(Irp
, IrpSp
, FALSE
, NULL
);
157 UINT ConnectDataSize
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
159 UNREFERENCED_PARAMETER(DeviceObject
);
161 if (!SocketAcquireStateLock(FCB
)) return LostSocket(Irp
);
164 return UnlockAndMaybeComplete(FCB
, STATUS_NO_MEMORY
, Irp
, 0);
166 if (FCB
->ConnectData
)
168 ExFreePool(FCB
->ConnectData
);
169 FCB
->ConnectData
= NULL
;
170 FCB
->ConnectDataSize
= 0;
171 FCB
->FilledConnectData
= 0;
174 FCB
->ConnectData
= ExAllocatePool(PagedPool
, ConnectDataSize
);
175 if (!FCB
->ConnectData
) return UnlockAndMaybeComplete(FCB
, STATUS_NO_MEMORY
, Irp
, 0);
177 RtlCopyMemory(FCB
->ConnectData
,
181 FCB
->ConnectDataSize
= ConnectDataSize
;
183 return UnlockAndMaybeComplete(FCB
, STATUS_SUCCESS
, Irp
, 0);
188 AfdSetConnectDataSize(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
189 PIO_STACK_LOCATION IrpSp
)
191 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
192 PAFD_FCB FCB
= FileObject
->FsContext
;
193 PUINT ConnectDataSize
= LockRequest(Irp
, IrpSp
, FALSE
, NULL
);
194 UINT BufferSize
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
196 UNREFERENCED_PARAMETER(DeviceObject
);
198 if (!SocketAcquireStateLock(FCB
)) return LostSocket(Irp
);
200 if (!ConnectDataSize
)
201 return UnlockAndMaybeComplete(FCB
, STATUS_NO_MEMORY
, Irp
, 0);
203 if (BufferSize
< sizeof(UINT
))
205 AFD_DbgPrint(MIN_TRACE
,("Buffer too small\n"));
206 return UnlockAndMaybeComplete(FCB
, STATUS_BUFFER_TOO_SMALL
, Irp
, 0);
209 if (FCB
->ConnectData
)
211 ExFreePool(FCB
->ConnectData
);
212 FCB
->ConnectDataSize
= 0;
213 FCB
->FilledConnectData
= 0;
216 FCB
->ConnectData
= ExAllocatePool(PagedPool
, *ConnectDataSize
);
217 if (!FCB
->ConnectData
) return UnlockAndMaybeComplete(FCB
, STATUS_NO_MEMORY
, Irp
, 0);
219 FCB
->ConnectDataSize
= *ConnectDataSize
;
221 return UnlockAndMaybeComplete(FCB
, STATUS_SUCCESS
, Irp
, 0);
226 WarmSocketForConnection(PAFD_FCB FCB
) {
229 if( !FCB
->TdiDeviceName
.Length
|| !FCB
->TdiDeviceName
.Buffer
) {
230 AFD_DbgPrint(MIN_TRACE
,("Null Device\n"));
231 return STATUS_NO_SUCH_DEVICE
;
234 Status
= TdiOpenConnectionEndpointFile(&FCB
->TdiDeviceName
,
235 &FCB
->Connection
.Handle
,
236 &FCB
->Connection
.Object
);
238 if( NT_SUCCESS(Status
) ) {
239 Status
= TdiAssociateAddressFile( FCB
->AddressFile
.Handle
,
240 FCB
->Connection
.Object
);
247 MakeSocketIntoConnection(PAFD_FCB FCB
) {
250 ASSERT(!FCB
->Recv
.Window
);
251 ASSERT(!FCB
->Send
.Window
);
255 Status
= TdiQueryMaxDatagramLength(FCB
->Connection
.Object
,
257 if (!NT_SUCCESS(Status
))
263 Status
= TdiQueryMaxDatagramLength(FCB
->Connection
.Object
,
265 if (!NT_SUCCESS(Status
))
269 /* Allocate the receive area and start receiving */
270 if (!FCB
->Recv
.Window
)
272 FCB
->Recv
.Window
= ExAllocatePool( PagedPool
, FCB
->Recv
.Size
);
273 if( !FCB
->Recv
.Window
) return STATUS_NO_MEMORY
;
276 if (!FCB
->Send
.Window
)
278 FCB
->Send
.Window
= ExAllocatePool( PagedPool
, FCB
->Send
.Size
);
279 if( !FCB
->Send
.Window
) return STATUS_NO_MEMORY
;
282 FCB
->State
= SOCKET_STATE_CONNECTED
;
284 Status
= TdiReceive( &FCB
->ReceiveIrp
.InFlightRequest
,
285 FCB
->Connection
.Object
,
292 if( Status
== STATUS_PENDING
) Status
= STATUS_SUCCESS
;
294 FCB
->PollState
|= AFD_EVENT_CONNECT
| AFD_EVENT_SEND
;
295 FCB
->PollStatus
[FD_CONNECT_BIT
] = STATUS_SUCCESS
;
296 FCB
->PollStatus
[FD_WRITE_BIT
] = STATUS_SUCCESS
;
297 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
302 static IO_COMPLETION_ROUTINE StreamSocketConnectComplete
;
306 StreamSocketConnectComplete(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
308 NTSTATUS Status
= Irp
->IoStatus
.Status
;
309 PAFD_FCB FCB
= (PAFD_FCB
)Context
;
310 PLIST_ENTRY NextIrpEntry
;
313 AFD_DbgPrint(MID_TRACE
,("Called: FCB %p, FO %p\n",
314 Context
, FCB
->FileObject
));
316 /* I was wrong about this before as we can have pending writes to a not
317 * yet connected socket */
318 if( !SocketAcquireStateLock( FCB
) )
319 return STATUS_FILE_CLOSED
;
321 AFD_DbgPrint(MID_TRACE
,("Irp->IoStatus.Status = %x\n",
322 Irp
->IoStatus
.Status
));
324 ASSERT(FCB
->ConnectIrp
.InFlightRequest
== Irp
);
325 FCB
->ConnectIrp
.InFlightRequest
= NULL
;
327 if( FCB
->State
== SOCKET_STATE_CLOSED
) {
328 /* Cleanup our IRP queue because the FCB is being destroyed */
329 while( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_CONNECT
] ) ) {
330 NextIrpEntry
= RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_CONNECT
]);
331 NextIrp
= CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
332 NextIrp
->IoStatus
.Status
= STATUS_FILE_CLOSED
;
333 NextIrp
->IoStatus
.Information
= 0;
334 if( NextIrp
->MdlAddress
) UnlockRequest( NextIrp
, IoGetCurrentIrpStackLocation( NextIrp
) );
335 (void)IoSetCancelRoutine(NextIrp
, NULL
);
336 IoCompleteRequest( NextIrp
, IO_NETWORK_INCREMENT
);
338 SocketStateUnlock( FCB
);
339 return STATUS_FILE_CLOSED
;
342 if( !NT_SUCCESS(Irp
->IoStatus
.Status
) ) {
343 FCB
->PollState
|= AFD_EVENT_CONNECT_FAIL
;
344 FCB
->PollStatus
[FD_CONNECT_BIT
] = Irp
->IoStatus
.Status
;
345 AFD_DbgPrint(MID_TRACE
,("Going to bound state\n"));
346 FCB
->State
= SOCKET_STATE_BOUND
;
347 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
350 /* Succeed pending irps on the FUNCTION_CONNECT list */
351 while( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_CONNECT
] ) ) {
352 NextIrpEntry
= RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_CONNECT
]);
353 NextIrp
= CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
354 AFD_DbgPrint(MID_TRACE
,("Completing connect %p\n", NextIrp
));
355 NextIrp
->IoStatus
.Status
= Status
;
356 NextIrp
->IoStatus
.Information
= NT_SUCCESS(Status
) ? ((ULONG_PTR
)FCB
->Connection
.Handle
) : 0;
357 if( NextIrp
->MdlAddress
) UnlockRequest( NextIrp
, IoGetCurrentIrpStackLocation( NextIrp
) );
358 (void)IoSetCancelRoutine(NextIrp
, NULL
);
359 IoCompleteRequest( NextIrp
, IO_NETWORK_INCREMENT
);
362 if( NT_SUCCESS(Status
) ) {
363 Status
= MakeSocketIntoConnection( FCB
);
365 if( !NT_SUCCESS(Status
) ) {
366 SocketStateUnlock( FCB
);
370 FCB
->FilledConnectData
= MIN(FCB
->ConnectReturnInfo
->UserDataLength
, FCB
->ConnectDataSize
);
371 if (FCB
->FilledConnectData
)
373 RtlCopyMemory(FCB
->ConnectData
,
374 FCB
->ConnectReturnInfo
->UserData
,
375 FCB
->FilledConnectData
);
378 FCB
->FilledConnectOptions
= MIN(FCB
->ConnectReturnInfo
->OptionsLength
, FCB
->ConnectOptionsSize
);
379 if (FCB
->FilledConnectOptions
)
381 RtlCopyMemory(FCB
->ConnectOptions
,
382 FCB
->ConnectReturnInfo
->Options
,
383 FCB
->FilledConnectOptions
);
386 if( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
387 NextIrpEntry
= RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
388 NextIrp
= CONTAINING_RECORD(NextIrpEntry
, IRP
,
389 Tail
.Overlay
.ListEntry
);
390 AFD_DbgPrint(MID_TRACE
,("Launching send request %p\n", NextIrp
));
391 Status
= AfdConnectedSocketWriteData
394 IoGetCurrentIrpStackLocation( NextIrp
),
398 if( Status
== STATUS_PENDING
)
399 Status
= STATUS_SUCCESS
;
402 SocketStateUnlock( FCB
);
404 AFD_DbgPrint(MID_TRACE
,("Returning %x\n", Status
));
409 /* Return the socket object for ths request only if it is a connected or
413 AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
414 PIO_STACK_LOCATION IrpSp
) {
415 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
416 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
417 PAFD_FCB FCB
= FileObject
->FsContext
;
418 PAFD_CONNECT_INFO ConnectReq
;
419 AFD_DbgPrint(MID_TRACE
,("Called on %p\n", FCB
));
421 UNREFERENCED_PARAMETER(DeviceObject
);
423 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
424 if( !(ConnectReq
= LockRequest( Irp
, IrpSp
, FALSE
, NULL
)) )
425 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
,
428 AFD_DbgPrint(MID_TRACE
,("Connect request:\n"));
432 IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
);
435 if( FCB
->Flags
& AFD_ENDPOINT_CONNECTIONLESS
)
437 if( FCB
->RemoteAddress
) ExFreePool( FCB
->RemoteAddress
);
439 TaCopyTransportAddress( &ConnectReq
->RemoteAddress
);
441 if( !FCB
->RemoteAddress
)
442 Status
= STATUS_NO_MEMORY
;
444 Status
= STATUS_SUCCESS
;
446 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
449 switch( FCB
->State
) {
450 case SOCKET_STATE_CONNECTED
:
451 Status
= STATUS_SUCCESS
;
454 case SOCKET_STATE_CONNECTING
:
455 return LeaveIrpUntilLater( FCB
, Irp
, FUNCTION_CONNECT
);
457 case SOCKET_STATE_CREATED
:
458 if( FCB
->LocalAddress
) ExFreePool( FCB
->LocalAddress
);
460 TaBuildNullTransportAddress( ConnectReq
->RemoteAddress
.Address
[0].AddressType
);
462 if( FCB
->LocalAddress
) {
463 Status
= WarmSocketForBind( FCB
, AFD_SHARE_WILDCARD
);
465 if( NT_SUCCESS(Status
) )
466 FCB
->State
= SOCKET_STATE_BOUND
;
468 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
470 return UnlockAndMaybeComplete
471 ( FCB
, STATUS_NO_MEMORY
, Irp
, 0 );
473 /* Drop through to SOCKET_STATE_BOUND */
475 case SOCKET_STATE_BOUND
:
476 if( FCB
->RemoteAddress
) ExFreePool( FCB
->RemoteAddress
);
478 TaCopyTransportAddress( &ConnectReq
->RemoteAddress
);
480 if( !FCB
->RemoteAddress
) {
481 Status
= STATUS_NO_MEMORY
;
485 Status
= WarmSocketForConnection( FCB
);
487 if( !NT_SUCCESS(Status
) )
490 if (FCB
->ConnectReturnInfo
) ExFreePool(FCB
->ConnectReturnInfo
);
491 Status
= TdiBuildConnectionInfo
492 ( &FCB
->ConnectReturnInfo
,
493 &ConnectReq
->RemoteAddress
);
495 if( NT_SUCCESS(Status
) )
497 if (FCB
->ConnectCallInfo
) ExFreePool(FCB
->ConnectCallInfo
);
498 Status
= TdiBuildConnectionInfo(&FCB
->ConnectCallInfo
,
499 &ConnectReq
->RemoteAddress
);
504 if( NT_SUCCESS(Status
) ) {
505 FCB
->ConnectCallInfo
->UserData
= FCB
->ConnectData
;
506 FCB
->ConnectCallInfo
->UserDataLength
= FCB
->ConnectDataSize
;
507 FCB
->ConnectCallInfo
->Options
= FCB
->ConnectOptions
;
508 FCB
->ConnectCallInfo
->OptionsLength
= FCB
->ConnectOptionsSize
;
510 FCB
->State
= SOCKET_STATE_CONNECTING
;
512 AFD_DbgPrint(MID_TRACE
,("Queueing IRP %p\n", Irp
));
513 Status
= QueueUserModeIrp( FCB
, Irp
, FUNCTION_CONNECT
);
514 if (Status
== STATUS_PENDING
)
516 Status
= TdiConnect( &FCB
->ConnectIrp
.InFlightRequest
,
517 FCB
->Connection
.Object
,
518 FCB
->ConnectCallInfo
,
519 FCB
->ConnectReturnInfo
,
520 StreamSocketConnectComplete
,
524 if (Status
!= STATUS_PENDING
)
525 FCB
->State
= SOCKET_STATE_BOUND
;
527 SocketStateUnlock(FCB
);
534 AFD_DbgPrint(MIN_TRACE
,("Inappropriate socket state %u for connect\n",
539 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );