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 if( !SocketAcquireStateLock( FCB
) )
42 return STATUS_FILE_CLOSED
;
44 FCB
->SendIrp
.InFlightRequest
= NULL
;
45 /* Request is not in flight any longer */
47 if( FCB
->State
== SOCKET_STATE_CLOSED
) {
48 /* Cleanup our IRP queue because the FCB is being destroyed */
49 while( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
50 NextIrpEntry
= RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
51 NextIrp
= CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
52 NextIrpSp
= IoGetCurrentIrpStackLocation( NextIrp
);
53 SendReq
= NextIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
54 NextIrp
->IoStatus
.Status
= STATUS_FILE_CLOSED
;
55 NextIrp
->IoStatus
.Information
= 0;
56 UnlockBuffers(SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
57 if( NextIrp
->MdlAddress
) UnlockRequest( NextIrp
, IoGetCurrentIrpStackLocation( NextIrp
) );
58 (void)IoSetCancelRoutine(NextIrp
, NULL
);
59 IoCompleteRequest( NextIrp
, IO_NETWORK_INCREMENT
);
61 SocketStateUnlock( FCB
);
62 return STATUS_FILE_CLOSED
;
65 if( !NT_SUCCESS(Status
) ) {
66 /* Complete all following send IRPs with error */
68 while( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
70 RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
72 CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
73 NextIrpSp
= IoGetCurrentIrpStackLocation( NextIrp
);
74 SendReq
= NextIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
76 UnlockBuffers( SendReq
->BufferArray
,
80 NextIrp
->IoStatus
.Status
= Status
;
81 NextIrp
->IoStatus
.Information
= 0;
83 if ( NextIrp
->MdlAddress
) UnlockRequest( NextIrp
, IoGetCurrentIrpStackLocation( NextIrp
) );
84 (void)IoSetCancelRoutine(NextIrp
, NULL
);
85 IoCompleteRequest( NextIrp
, IO_NETWORK_INCREMENT
);
88 SocketStateUnlock( FCB
);
90 return STATUS_SUCCESS
;
93 RtlMoveMemory( FCB
->Send
.Window
,
94 FCB
->Send
.Window
+ FCB
->Send
.BytesUsed
,
95 FCB
->Send
.BytesUsed
- Irp
->IoStatus
.Information
);
96 FCB
->Send
.BytesUsed
-= Irp
->IoStatus
.Information
;
98 if( !FCB
->Send
.BytesUsed
&&
99 !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
101 RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
103 CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
104 NextIrpSp
= IoGetCurrentIrpStackLocation( NextIrp
);
105 SendReq
= NextIrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
106 Map
= (PAFD_MAPBUF
)(SendReq
->BufferArray
+ SendReq
->BufferCount
);
108 AFD_DbgPrint(MID_TRACE
,("SendReq @ %x\n", SendReq
));
110 SpaceAvail
= FCB
->Send
.Size
- FCB
->Send
.BytesUsed
;
112 for( i
= 0; i
< SendReq
->BufferCount
; i
++ ) {
113 Map
[i
].BufferAddress
=
114 MmMapLockedPages( Map
[i
].Mdl
, KernelMode
);
116 CopySize
= MIN( SpaceAvail
,
117 SendReq
->BufferArray
[i
].len
);
119 RtlCopyMemory( FCB
->Send
.Window
+ FCB
->Send
.BytesUsed
,
120 Map
[i
].BufferAddress
,
123 MmUnmapLockedPages( Map
[i
].BufferAddress
, Map
[i
].Mdl
);
125 FCB
->Send
.BytesUsed
+= CopySize
;
126 TotalBytesCopied
+= CopySize
;
127 SpaceAvail
-= CopySize
;
131 /* Some data is still waiting */
132 if( FCB
->Send
.BytesUsed
) {
133 FCB
->PollState
&= ~AFD_EVENT_SEND
;
135 Status
= TdiSend( &FCB
->SendIrp
.InFlightRequest
,
136 FCB
->Connection
.Object
,
144 FCB
->PollState
|= AFD_EVENT_SEND
;
147 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
149 if( TotalBytesCopied
> 0 ) {
150 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
152 if( Status
== STATUS_PENDING
)
153 Status
= STATUS_SUCCESS
;
155 AFD_DbgPrint(MID_TRACE
,("Dismissing request: %x\n", Status
));
157 return UnlockAndMaybeComplete( FCB
, Status
, NextIrp
, TotalBytesCopied
);
158 } else if( NextIrp
) {
159 AFD_DbgPrint(MID_TRACE
,("Could not do any more with Irp %x\n",
161 InsertHeadList( &FCB
->PendingIrpList
[FUNCTION_SEND
],
162 &NextIrp
->Tail
.Overlay
.ListEntry
);
165 SocketStateUnlock( FCB
);
167 return STATUS_SUCCESS
;
170 static NTSTATUS NTAPI PacketSocketSendComplete
171 ( PDEVICE_OBJECT DeviceObject
,
174 PAFD_FCB FCB
= (PAFD_FCB
)Context
;
175 PLIST_ENTRY NextIrpEntry
;
178 AFD_DbgPrint(MID_TRACE
,("Called, status %x, %d bytes used\n",
179 Irp
->IoStatus
.Status
,
180 Irp
->IoStatus
.Information
));
182 if( !SocketAcquireStateLock( FCB
) )
183 return STATUS_FILE_CLOSED
;
185 FCB
->SendIrp
.InFlightRequest
= NULL
;
186 /* Request is not in flight any longer */
188 FCB
->PollState
|= AFD_EVENT_SEND
;
189 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
191 if( FCB
->State
== SOCKET_STATE_CLOSED
) {
192 /* Cleanup our IRP queue because the FCB is being destroyed */
193 while( !IsListEmpty( &FCB
->PendingIrpList
[FUNCTION_SEND
] ) ) {
194 NextIrpEntry
= RemoveHeadList(&FCB
->PendingIrpList
[FUNCTION_SEND
]);
195 NextIrp
= CONTAINING_RECORD(NextIrpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
196 NextIrp
->IoStatus
.Status
= STATUS_FILE_CLOSED
;
197 NextIrp
->IoStatus
.Information
= 0;
198 if( NextIrp
->MdlAddress
) UnlockRequest( NextIrp
, IoGetCurrentIrpStackLocation( NextIrp
) );
199 (void)IoSetCancelRoutine(NextIrp
, NULL
);
200 IoCompleteRequest( NextIrp
, IO_NETWORK_INCREMENT
);
202 SocketStateUnlock( FCB
);
203 return STATUS_FILE_CLOSED
;
206 SocketStateUnlock( FCB
);
208 return STATUS_SUCCESS
;
212 AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
213 PIO_STACK_LOCATION IrpSp
, BOOLEAN Short
) {
214 NTSTATUS Status
= STATUS_SUCCESS
;
215 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
216 PAFD_FCB FCB
= FileObject
->FsContext
;
217 PAFD_SEND_INFO SendReq
;
219 UINT TotalBytesCopied
= 0, i
, CopySize
= 0,
220 SpaceAvail
= 0, TotalBytesEncountered
= 0;
222 AFD_DbgPrint(MID_TRACE
,("Called on %x\n", FCB
));
224 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
226 if( FCB
->Flags
& AFD_ENDPOINT_CONNECTIONLESS
)
228 PAFD_SEND_INFO_UDP SendReq
;
229 PTDI_CONNECTION_INFORMATION TargetAddress
;
231 /* Check that the socket is bound */
232 if( FCB
->State
!= SOCKET_STATE_BOUND
)
233 return UnlockAndMaybeComplete( FCB
, STATUS_INVALID_PARAMETER
, Irp
,
236 if( !(SendReq
= LockRequest( Irp
, IrpSp
)) )
237 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
, 0 );
239 /* Must lock buffers before handing off user data */
240 SendReq
->BufferArray
= LockBuffers( SendReq
->BufferArray
,
241 SendReq
->BufferCount
,
245 if( !SendReq
->BufferArray
) {
246 return UnlockAndMaybeComplete( FCB
, STATUS_ACCESS_VIOLATION
,
250 TdiBuildConnectionInfo( &TargetAddress
, FCB
->RemoteAddress
);
252 if( TargetAddress
) {
253 Status
= TdiSendDatagram
254 ( &FCB
->SendIrp
.InFlightRequest
,
255 FCB
->AddressFile
.Object
,
256 SendReq
->BufferArray
[0].buf
,
257 SendReq
->BufferArray
[0].len
,
260 PacketSocketSendComplete
,
263 ExFreePool( TargetAddress
);
264 } else Status
= STATUS_NO_MEMORY
;
266 if( Status
== STATUS_PENDING
) Status
= STATUS_SUCCESS
;
268 AFD_DbgPrint(MID_TRACE
,("Dismissing request: %x\n", Status
));
270 /* Even if we were pended, we're done with the user buffer at this
272 Information
= SendReq
->BufferArray
[0].len
;
273 UnlockBuffers(SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
274 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, Information
);
277 if( !(SendReq
= LockRequest( Irp
, IrpSp
)) )
278 return UnlockAndMaybeComplete
279 ( FCB
, STATUS_NO_MEMORY
, Irp
, TotalBytesCopied
);
281 SendReq
->BufferArray
= LockBuffers( SendReq
->BufferArray
,
282 SendReq
->BufferCount
,
286 if( !SendReq
->BufferArray
) {
287 return UnlockAndMaybeComplete( FCB
, STATUS_ACCESS_VIOLATION
,
291 AFD_DbgPrint(MID_TRACE
,("Socket state %d\n", FCB
->State
));
293 if( FCB
->State
!= SOCKET_STATE_CONNECTED
) {
294 if( SendReq
->AfdFlags
& AFD_IMMEDIATE
) {
295 AFD_DbgPrint(MID_TRACE
,("Nonblocking\n"));
296 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
297 return UnlockAndMaybeComplete
298 ( FCB
, STATUS_CANT_WAIT
, Irp
, 0 );
300 AFD_DbgPrint(MID_TRACE
,("Queuing request\n"));
301 return LeaveIrpUntilLater( FCB
, Irp
, FUNCTION_SEND
);
305 AFD_DbgPrint(MID_TRACE
,("FCB->Send.BytesUsed = %d\n",
306 FCB
->Send
.BytesUsed
));
308 if( !FCB
->Send
.BytesUsed
) {
309 SpaceAvail
= FCB
->Send
.Size
- FCB
->Send
.BytesUsed
;
311 AFD_DbgPrint(MID_TRACE
,("We can accept %d bytes\n",
314 for( i
= 0; FCB
->Send
.BytesUsed
< FCB
->Send
.Size
&&
315 i
< SendReq
->BufferCount
; i
++ ) {
316 CopySize
= MIN( SpaceAvail
,
317 SendReq
->BufferArray
[i
].len
);
319 TotalBytesEncountered
+= SendReq
->BufferArray
[i
].len
;
321 AFD_DbgPrint(MID_TRACE
,("Copying Buffer %d, %x:%d to %x\n",
323 SendReq
->BufferArray
[i
].buf
,
325 FCB
->Send
.Window
+ FCB
->Send
.BytesUsed
));
327 RtlCopyMemory( FCB
->Send
.Window
+ FCB
->Send
.BytesUsed
,
328 SendReq
->BufferArray
[i
].buf
,
331 FCB
->Send
.BytesUsed
+= CopySize
;
332 TotalBytesCopied
+= CopySize
;
333 SpaceAvail
-= CopySize
;
336 if( TotalBytesEncountered
== 0 ) {
337 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
339 AFD_DbgPrint(MID_TRACE
,("Empty send\n"));
340 return UnlockAndMaybeComplete
341 ( FCB
, Status
, Irp
, TotalBytesCopied
);
344 AFD_DbgPrint(MID_TRACE
,("Completed %d bytes\n", TotalBytesCopied
));
346 if( TotalBytesCopied
> 0 ) {
347 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
349 Status
= TdiSend( &FCB
->SendIrp
.InFlightRequest
,
350 FCB
->Connection
.Object
,
358 if( Status
== STATUS_PENDING
)
359 Status
= STATUS_SUCCESS
;
361 AFD_DbgPrint(MID_TRACE
,("Dismissing request: %x (%d)\n",
362 Status
, TotalBytesCopied
));
364 return UnlockAndMaybeComplete
365 ( FCB
, Status
, Irp
, TotalBytesCopied
);
369 if( SendReq
->AfdFlags
& AFD_IMMEDIATE
) {
370 AFD_DbgPrint(MID_TRACE
,("Nonblocking\n"));
371 UnlockBuffers( SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
372 return UnlockAndMaybeComplete
373 ( FCB
, STATUS_CANT_WAIT
, Irp
, 0 );
375 AFD_DbgPrint(MID_TRACE
,("Queuing request\n"));
376 return LeaveIrpUntilLater( FCB
, Irp
, FUNCTION_SEND
);
381 AfdPacketSocketWriteData(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
382 PIO_STACK_LOCATION IrpSp
) {
383 NTSTATUS Status
= STATUS_SUCCESS
;
384 PTDI_CONNECTION_INFORMATION TargetAddress
;
385 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
386 PAFD_FCB FCB
= FileObject
->FsContext
;
387 PAFD_SEND_INFO_UDP SendReq
;
390 AFD_DbgPrint(MID_TRACE
,("Called on %x\n", FCB
));
392 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
394 FCB
->PollState
&= ~AFD_EVENT_SEND
;
396 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
398 /* Check that the socket is bound */
399 if( FCB
->State
!= SOCKET_STATE_BOUND
)
400 return UnlockAndMaybeComplete
401 ( FCB
, STATUS_INVALID_PARAMETER
, Irp
, 0 );
402 if( !(SendReq
= LockRequest( Irp
, IrpSp
)) )
403 return UnlockAndMaybeComplete
404 ( FCB
, STATUS_NO_MEMORY
, Irp
, 0 );
406 SendReq
->BufferArray
= LockBuffers( SendReq
->BufferArray
,
407 SendReq
->BufferCount
,
411 if( !SendReq
->BufferArray
)
412 return UnlockAndMaybeComplete( FCB
, STATUS_ACCESS_VIOLATION
,
416 (MID_TRACE
,("RemoteAddress #%d Type %d\n",
417 ((PTRANSPORT_ADDRESS
)SendReq
->TdiConnection
.RemoteAddress
)->
419 ((PTRANSPORT_ADDRESS
)SendReq
->TdiConnection
.RemoteAddress
)->
420 Address
[0].AddressType
));
422 TdiBuildConnectionInfo( &TargetAddress
,
423 ((PTRANSPORT_ADDRESS
)SendReq
->TdiConnection
.RemoteAddress
) );
425 /* Check the size of the Address given ... */
427 if( TargetAddress
) {
428 Status
= TdiSendDatagram
429 ( &FCB
->SendIrp
.InFlightRequest
,
430 FCB
->AddressFile
.Object
,
431 SendReq
->BufferArray
[0].buf
,
432 SendReq
->BufferArray
[0].len
,
435 PacketSocketSendComplete
,
438 ExFreePool( TargetAddress
);
439 } else Status
= STATUS_NO_MEMORY
;
441 if( Status
== STATUS_PENDING
) Status
= STATUS_SUCCESS
;
443 AFD_DbgPrint(MID_TRACE
,("Dismissing request: %x\n", Status
));
445 /* Even if we were pended, we're done with the user buffer at this
447 Information
= SendReq
->BufferArray
[0].len
;
448 UnlockBuffers(SendReq
->BufferArray
, SendReq
->BufferCount
, FALSE
);
449 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, Information
);