2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/write.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
11 #include "tdi_proto.h"
15 static NTSTATUS NTAPI SendComplete
16 ( PDEVICE_OBJECT DeviceObject
,
19 NTSTATUS Status
= Irp
->IoStatus
.Status
;
20 PAFD_FCB FCB
= (PAFD_FCB
)Context
;
21 PLIST_ENTRY NextIrpEntry
;
23 PIO_STACK_LOCATION NextIrpSp
;
24 PAFD_SEND_INFO SendReq
= NULL
;
26 UINT TotalBytesCopied
= 0, SpaceAvail
, i
, CopySize
= 0;
29 * The Irp parameter passed in is the IRP of the stream between AFD and
30 * TDI driver. It's not very usefull to us. We need the IRPs of the stream
31 * between usermode and AFD. Those are chained from
32 * FCB->PendingIrpList[FUNCTION_SEND] and you'll see them in the code
33 * below as "NextIrp" ('cause they are the next usermode IRP to be
37 AFD_DbgPrint(MID_TRACE
,("Called, status %x, %d bytes used\n",
39 Irp
->IoStatus
.Information
));
41 ASSERT_IRQL(APC_LEVEL
);
43 if( !SocketAcquireStateLock( FCB
) )
44 return STATUS_FILE_CLOSED
;
46 FCB
->SendIrp
.InFlightRequest
= NULL
;
47 /* Request is not in flight any longer */
49 if( FCB
->State
== SOCKET_STATE_CLOSED
) {
50 /* Cleanup our IRP queue because the FCB is being destroyed */
51 while( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
52 NextIrpEntry
= RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
53 NextIrp
= CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
54 NextIrpSp
= IoGetCurrentIrpStackLocation( NextIrp
);
55 SendReq
= NextIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
56 NextIrp
->IoStatus
.Status
= STATUS_FILE_CLOSED
;
57 NextIrp
->IoStatus
.Information
= 0;
58 UnlockBuffers(SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
59 if( NextIrp
->MdlAddress
) UnlockRequest( NextIrp
, IoGetCurrentIrpStackLocation( NextIrp
) );
60 (void)IoSetCancelRoutine(NextIrp
, NULL
);
61 IoCompleteRequest( NextIrp
, IO_NETWORK_INCREMENT
);
63 SocketStateUnlock( FCB
);
64 return STATUS_FILE_CLOSED
;
67 if( !NT_SUCCESS(Status
) ) {
68 /* Complete all following send IRPs with error */
70 while( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
72 RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
74 CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
75 NextIrpSp
= IoGetCurrentIrpStackLocation( NextIrp
);
76 SendReq
= NextIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
78 UnlockBuffers( SendReq
->BufferArray
,
82 NextIrp
->IoStatus
.Status
= Status
;
83 NextIrp
->IoStatus
.Information
= 0;
85 if ( NextIrp
->MdlAddress
) UnlockRequest( NextIrp
, IoGetCurrentIrpStackLocation( NextIrp
) );
86 (void)IoSetCancelRoutine(NextIrp
, NULL
);
87 IoCompleteRequest( NextIrp
, IO_NETWORK_INCREMENT
);
90 SocketStateUnlock( FCB
);
92 return STATUS_SUCCESS
;
95 RtlMoveMemory( FCB
->Send
.Window
,
96 FCB
->Send
.Window
+ FCB
->Send
.BytesUsed
,
97 FCB
->Send
.BytesUsed
- Irp
->IoStatus
.Information
);
98 FCB
->Send
.BytesUsed
-= Irp
->IoStatus
.Information
;
100 if( !FCB
->Send
.BytesUsed
&&
101 !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
103 RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
105 CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
106 NextIrpSp
= IoGetCurrentIrpStackLocation( NextIrp
);
107 SendReq
= NextIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
108 Map
= (PAFD_MAPBUF
)(SendReq
->BufferArray
+ SendReq
->BufferCount
);
110 AFD_DbgPrint(MID_TRACE
,("SendReq @ %x\n", SendReq
));
112 SpaceAvail
= FCB
->Send
.Size
- FCB
->Send
.BytesUsed
;
114 for( i
= 0; i
< SendReq
->BufferCount
; i
++ ) {
115 Map
[i
].BufferAddress
=
116 MmMapLockedPages( Map
[i
].Mdl
, KernelMode
);
118 CopySize
= MIN( SpaceAvail
,
119 SendReq
->BufferArray
[i
].len
);
121 RtlCopyMemory( FCB
->Send
.Window
+ FCB
->Send
.BytesUsed
,
122 Map
[i
].BufferAddress
,
125 MmUnmapLockedPages( Map
[i
].BufferAddress
, Map
[i
].Mdl
);
127 FCB
->Send
.BytesUsed
+= CopySize
;
128 TotalBytesCopied
+= CopySize
;
129 SpaceAvail
-= CopySize
;
133 /* Some data is still waiting */
134 if( FCB
->Send
.BytesUsed
) {
135 FCB
->PollState
&= ~AFD_EVENT_SEND
;
137 Status
= TdiSend( &FCB
->SendIrp
.InFlightRequest
,
138 FCB
->Connection
.Object
,
146 FCB
->PollState
|= AFD_EVENT_SEND
;
149 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
151 if( TotalBytesCopied
> 0 ) {
152 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
154 if( Status
== STATUS_PENDING
)
155 Status
= STATUS_SUCCESS
;
157 AFD_DbgPrint(MID_TRACE
,("Dismissing request: %x\n", Status
));
159 return UnlockAndMaybeComplete( FCB
, Status
, NextIrp
, TotalBytesCopied
);
160 } else if( NextIrp
) {
161 AFD_DbgPrint(MID_TRACE
,("Could not do any more with Irp %x\n",
163 InsertHeadList( &FCB
->PendingIrpList
[FUNCTION_SEND
],
164 &NextIrp
->Tail
.Overlay
.ListEntry
);
167 SocketStateUnlock( FCB
);
169 return STATUS_SUCCESS
;
172 static NTSTATUS NTAPI PacketSocketSendComplete
173 ( PDEVICE_OBJECT DeviceObject
,
176 PAFD_FCB FCB
= (PAFD_FCB
)Context
;
177 PLIST_ENTRY NextIrpEntry
;
180 AFD_DbgPrint(MID_TRACE
,("Called, status %x, %d bytes used\n",
181 Irp
->IoStatus
.Status
,
182 Irp
->IoStatus
.Information
));
184 if( !SocketAcquireStateLock( FCB
) )
185 return STATUS_FILE_CLOSED
;
187 FCB
->SendIrp
.InFlightRequest
= NULL
;
188 /* Request is not in flight any longer */
190 FCB
->PollState
|= AFD_EVENT_SEND
;
191 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
193 if( FCB
->State
== SOCKET_STATE_CLOSED
) {
194 /* Cleanup our IRP queue because the FCB is being destroyed */
195 while( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
196 NextIrpEntry
= RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
197 NextIrp
= CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
198 NextIrp
->IoStatus
.Status
= STATUS_FILE_CLOSED
;
199 NextIrp
->IoStatus
.Information
= 0;
200 if( NextIrp
->MdlAddress
) UnlockRequest( NextIrp
, IoGetCurrentIrpStackLocation( NextIrp
) );
201 (void)IoSetCancelRoutine(NextIrp
, NULL
);
202 IoCompleteRequest( NextIrp
, IO_NETWORK_INCREMENT
);
204 SocketStateUnlock( FCB
);
205 return STATUS_FILE_CLOSED
;
208 SocketStateUnlock( FCB
);
210 return STATUS_SUCCESS
;
214 AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
215 PIO_STACK_LOCATION IrpSp
, BOOLEAN Short
) {
216 NTSTATUS Status
= STATUS_SUCCESS
;
217 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
218 PAFD_FCB FCB
= FileObject
->FsContext
;
219 PAFD_SEND_INFO SendReq
;
221 UINT TotalBytesCopied
= 0, i
, CopySize
= 0,
222 SpaceAvail
= 0, TotalBytesEncountered
= 0;
224 AFD_DbgPrint(MID_TRACE
,("Called on %x\n", FCB
));
226 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
228 if( FCB
->Flags
& AFD_ENDPOINT_CONNECTIONLESS
)
230 PAFD_SEND_INFO_UDP SendReq
;
231 PTDI_CONNECTION_INFORMATION TargetAddress
;
233 /* Check that the socket is bound */
234 if( FCB
->State
!= SOCKET_STATE_BOUND
)
235 return UnlockAndMaybeComplete( FCB
, STATUS_INVALID_PARAMETER
, Irp
,
238 if( !(SendReq
= LockRequest( Irp
, IrpSp
)) )
239 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
, 0 );
241 /* Must lock buffers before handing off user data */
242 SendReq
->BufferArray
= LockBuffers( SendReq
->BufferArray
,
243 SendReq
->BufferCount
,
247 if( !SendReq
->BufferArray
) {
248 return UnlockAndMaybeComplete( FCB
, STATUS_ACCESS_VIOLATION
,
252 TdiBuildConnectionInfo( &TargetAddress
, FCB
->RemoteAddress
);
254 if( TargetAddress
) {
255 Status
= TdiSendDatagram
256 ( &FCB
->SendIrp
.InFlightRequest
,
257 FCB
->AddressFile
.Object
,
258 SendReq
->BufferArray
[0].buf
,
259 SendReq
->BufferArray
[0].len
,
262 PacketSocketSendComplete
,
265 ExFreePool( TargetAddress
);
266 } else Status
= STATUS_NO_MEMORY
;
268 if( Status
== STATUS_PENDING
) Status
= STATUS_SUCCESS
;
270 AFD_DbgPrint(MID_TRACE
,("Dismissing request: %x\n", Status
));
272 /* Even if we were pended, we're done with the user buffer at this
274 Information
= SendReq
->BufferArray
[0].len
;
275 UnlockBuffers(SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
276 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, Information
);
279 if( !(SendReq
= LockRequest( Irp
, IrpSp
)) )
280 return UnlockAndMaybeComplete
281 ( FCB
, STATUS_NO_MEMORY
, Irp
, TotalBytesCopied
);
283 SendReq
->BufferArray
= LockBuffers( SendReq
->BufferArray
,
284 SendReq
->BufferCount
,
288 if( !SendReq
->BufferArray
) {
289 return UnlockAndMaybeComplete( FCB
, STATUS_ACCESS_VIOLATION
,
293 AFD_DbgPrint(MID_TRACE
,("Socket state %d\n", FCB
->State
));
295 if( FCB
->State
!= SOCKET_STATE_CONNECTED
) {
296 if( SendReq
->AfdFlags
& AFD_IMMEDIATE
) {
297 AFD_DbgPrint(MID_TRACE
,("Nonblocking\n"));
298 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
299 return UnlockAndMaybeComplete
300 ( FCB
, STATUS_CANT_WAIT
, Irp
, 0 );
302 AFD_DbgPrint(MID_TRACE
,("Queuing request\n"));
303 return LeaveIrpUntilLater( FCB
, Irp
, FUNCTION_SEND
);
307 AFD_DbgPrint(MID_TRACE
,("FCB->Send.BytesUsed = %d\n",
308 FCB
->Send
.BytesUsed
));
310 if( !FCB
->Send
.BytesUsed
) {
311 SpaceAvail
= FCB
->Send
.Size
- FCB
->Send
.BytesUsed
;
313 AFD_DbgPrint(MID_TRACE
,("We can accept %d bytes\n",
316 for( i
= 0; FCB
->Send
.BytesUsed
< FCB
->Send
.Size
&&
317 i
< SendReq
->BufferCount
; i
++ ) {
318 CopySize
= MIN( SpaceAvail
,
319 SendReq
->BufferArray
[i
].len
);
321 TotalBytesEncountered
+= SendReq
->BufferArray
[i
].len
;
323 AFD_DbgPrint(MID_TRACE
,("Copying Buffer %d, %x:%d to %x\n",
325 SendReq
->BufferArray
[i
].buf
,
327 FCB
->Send
.Window
+ FCB
->Send
.BytesUsed
));
329 RtlCopyMemory( FCB
->Send
.Window
+ FCB
->Send
.BytesUsed
,
330 SendReq
->BufferArray
[i
].buf
,
333 FCB
->Send
.BytesUsed
+= CopySize
;
334 TotalBytesCopied
+= CopySize
;
335 SpaceAvail
-= CopySize
;
338 if( TotalBytesEncountered
== 0 ) {
339 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
341 AFD_DbgPrint(MID_TRACE
,("Empty send\n"));
342 return UnlockAndMaybeComplete
343 ( FCB
, Status
, Irp
, TotalBytesCopied
);
346 AFD_DbgPrint(MID_TRACE
,("Completed %d bytes\n", TotalBytesCopied
));
348 if( TotalBytesCopied
> 0 ) {
349 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
351 Status
= TdiSend( &FCB
->SendIrp
.InFlightRequest
,
352 FCB
->Connection
.Object
,
360 if( Status
== STATUS_PENDING
)
361 Status
= STATUS_SUCCESS
;
363 AFD_DbgPrint(MID_TRACE
,("Dismissing request: %x (%d)\n",
364 Status
, TotalBytesCopied
));
366 return UnlockAndMaybeComplete
367 ( FCB
, Status
, Irp
, TotalBytesCopied
);
371 if( SendReq
->AfdFlags
& AFD_IMMEDIATE
) {
372 AFD_DbgPrint(MID_TRACE
,("Nonblocking\n"));
373 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
374 return UnlockAndMaybeComplete
375 ( FCB
, STATUS_CANT_WAIT
, Irp
, 0 );
377 AFD_DbgPrint(MID_TRACE
,("Queuing request\n"));
378 return LeaveIrpUntilLater( FCB
, Irp
, FUNCTION_SEND
);
383 AfdPacketSocketWriteData(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
384 PIO_STACK_LOCATION IrpSp
) {
385 NTSTATUS Status
= STATUS_SUCCESS
;
386 PTDI_CONNECTION_INFORMATION TargetAddress
;
387 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
388 PAFD_FCB FCB
= FileObject
->FsContext
;
389 PAFD_SEND_INFO_UDP SendReq
;
392 AFD_DbgPrint(MID_TRACE
,("Called on %x\n", FCB
));
394 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
396 FCB
->PollState
&= ~AFD_EVENT_SEND
;
398 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
400 /* Check that the socket is bound */
401 if( FCB
->State
!= SOCKET_STATE_BOUND
)
402 return UnlockAndMaybeComplete
403 ( FCB
, STATUS_INVALID_PARAMETER
, Irp
, 0 );
404 if( !(SendReq
= LockRequest( Irp
, IrpSp
)) )
405 return UnlockAndMaybeComplete
406 ( FCB
, STATUS_NO_MEMORY
, Irp
, 0 );
408 SendReq
->BufferArray
= LockBuffers( SendReq
->BufferArray
,
409 SendReq
->BufferCount
,
413 if( !SendReq
->BufferArray
)
414 return UnlockAndMaybeComplete( FCB
, STATUS_ACCESS_VIOLATION
,
418 (MID_TRACE
,("RemoteAddress #%d Type %d\n",
419 ((PTRANSPORT_ADDRESS
)SendReq
->TdiConnection
.RemoteAddress
)->
421 ((PTRANSPORT_ADDRESS
)SendReq
->TdiConnection
.RemoteAddress
)->
422 Address
[0].AddressType
));
424 TdiBuildConnectionInfo( &TargetAddress
,
425 ((PTRANSPORT_ADDRESS
)SendReq
->TdiConnection
.RemoteAddress
) );
427 /* Check the size of the Address given ... */
429 if( TargetAddress
) {
430 Status
= TdiSendDatagram
431 ( &FCB
->SendIrp
.InFlightRequest
,
432 FCB
->AddressFile
.Object
,
433 SendReq
->BufferArray
[0].buf
,
434 SendReq
->BufferArray
[0].len
,
437 PacketSocketSendComplete
,
440 ExFreePool( TargetAddress
);
441 } else Status
= STATUS_NO_MEMORY
;
443 if( Status
== STATUS_PENDING
) Status
= STATUS_SUCCESS
;
445 AFD_DbgPrint(MID_TRACE
,("Dismissing request: %x\n", Status
));
447 /* Even if we were pended, we're done with the user buffer at this
449 Information
= SendReq
->BufferArray
[0].len
;
450 UnlockBuffers(SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
451 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, Information
);