- Fix handling of cancelled IRPs
[reactos.git] / drivers / network / afd / afd / write.c
1 /*
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)
7 * UPDATE HISTORY:
8 * 20040708 Created
9 */
10 #include "afd.h"
11 #include "tdi_proto.h"
12 #include "tdiconn.h"
13 #include "debug.h"
14
15 static NTSTATUS NTAPI SendComplete
16 ( PDEVICE_OBJECT DeviceObject,
17 PIRP Irp,
18 PVOID Context ) {
19 NTSTATUS Status = Irp->IoStatus.Status;
20 PAFD_FCB FCB = (PAFD_FCB)Context;
21 PLIST_ENTRY NextIrpEntry;
22 PIRP NextIrp = NULL;
23 PIO_STACK_LOCATION NextIrpSp;
24 PAFD_SEND_INFO SendReq = NULL;
25 PAFD_MAPBUF Map;
26 UINT TotalBytesCopied = 0, SpaceAvail, i, CopySize = 0;
27
28 /*
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
34 * processed).
35 */
36
37 AFD_DbgPrint(MID_TRACE,("Called, status %x, %d bytes used\n",
38 Irp->IoStatus.Status,
39 Irp->IoStatus.Information));
40
41 ASSERT_IRQL(APC_LEVEL);
42
43 if( Irp->Cancel ) {
44 if( FCB ) FCB->SendIrp.InFlightRequest = NULL;
45 return STATUS_CANCELLED;
46 }
47
48 if( !SocketAcquireStateLock( FCB ) ) return Status;
49
50 FCB->SendIrp.InFlightRequest = NULL;
51 /* Request is not in flight any longer */
52
53 if( FCB->State == SOCKET_STATE_CLOSED ) {
54 SocketStateUnlock( FCB );
55 return STATUS_SUCCESS;
56 }
57
58 if( !NT_SUCCESS(Status) ) {
59 /* Complete all following send IRPs with error */
60
61 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
62 NextIrpEntry =
63 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
64 NextIrp =
65 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
66 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
67 SendReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
68
69 UnlockBuffers( SendReq->BufferArray,
70 SendReq->BufferCount,
71 FALSE );
72
73 NextIrp->IoStatus.Status = Status;
74 NextIrp->IoStatus.Information = 0;
75
76 if ( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
77
78 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
79 }
80
81 SocketStateUnlock( FCB );
82
83 return STATUS_SUCCESS;
84 }
85
86 RtlMoveMemory( FCB->Send.Window,
87 FCB->Send.Window + FCB->Send.BytesUsed,
88 FCB->Send.BytesUsed - Irp->IoStatus.Information );
89 FCB->Send.BytesUsed -= Irp->IoStatus.Information;
90
91 if( !FCB->Send.BytesUsed &&
92 !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
93 NextIrpEntry =
94 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
95 NextIrp =
96 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
97 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
98 SendReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
99 Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount);
100
101 AFD_DbgPrint(MID_TRACE,("SendReq @ %x\n", SendReq));
102
103 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
104
105 for( i = 0; i < SendReq->BufferCount; i++ ) {
106 Map[i].BufferAddress =
107 MmMapLockedPages( Map[i].Mdl, KernelMode );
108
109 CopySize = MIN( SpaceAvail,
110 SendReq->BufferArray[i].len );
111
112 RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
113 Map[i].BufferAddress,
114 CopySize );
115
116 MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
117
118 FCB->Send.BytesUsed += CopySize;
119 TotalBytesCopied += CopySize;
120 SpaceAvail -= CopySize;
121 }
122 }
123
124 /* Some data is still waiting */
125 if( FCB->Send.BytesUsed ) {
126 FCB->PollState &= ~AFD_EVENT_SEND;
127
128 SocketCalloutEnter( FCB );
129
130 Status = TdiSend( &FCB->SendIrp.InFlightRequest,
131 FCB->Connection.Object,
132 0,
133 FCB->Send.Window,
134 FCB->Send.BytesUsed,
135 &FCB->SendIrp.Iosb,
136 SendComplete,
137 FCB );
138
139 SocketCalloutLeave( FCB );
140 } else {
141 FCB->PollState |= AFD_EVENT_SEND;
142 PollReeval( FCB->DeviceExt, FCB->FileObject );
143 }
144
145 if( TotalBytesCopied > 0 ) {
146 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
147
148 if( Status == STATUS_PENDING )
149 Status = STATUS_SUCCESS;
150
151 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
152
153 return UnlockAndMaybeComplete( FCB, Status, NextIrp, TotalBytesCopied,
154 NULL );
155 } else if( NextIrp ) {
156 AFD_DbgPrint(MID_TRACE,("Could not do any more with Irp %x\n",
157 NextIrp));
158 InsertHeadList( &FCB->PendingIrpList[FUNCTION_SEND],
159 &NextIrp->Tail.Overlay.ListEntry );
160 }
161
162 SocketStateUnlock( FCB );
163
164 return STATUS_SUCCESS;
165 }
166
167 static NTSTATUS NTAPI PacketSocketSendComplete
168 ( PDEVICE_OBJECT DeviceObject,
169 PIRP Irp,
170 PVOID Context ) {
171 PAFD_FCB FCB = (PAFD_FCB)Context;
172
173 AFD_DbgPrint(MID_TRACE,("Called, status %x, %d bytes used\n",
174 Irp->IoStatus.Status,
175 Irp->IoStatus.Information));
176
177 if( Irp->Cancel ) {
178 if( FCB ) FCB->SendIrp.InFlightRequest = NULL;
179 return STATUS_CANCELLED;
180 }
181
182 /* It's ok if the FCB already died */
183 if( !SocketAcquireStateLock( FCB ) ) return STATUS_SUCCESS;
184
185 FCB->PollState |= AFD_EVENT_SEND;
186 PollReeval( FCB->DeviceExt, FCB->FileObject );
187
188 FCB->SendIrp.InFlightRequest = NULL;
189 /* Request is not in flight any longer */
190
191 SocketStateUnlock( FCB );
192
193 return STATUS_SUCCESS;
194 }
195
196 NTSTATUS STDCALL
197 AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
198 PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
199 NTSTATUS Status = STATUS_SUCCESS;
200 PFILE_OBJECT FileObject = IrpSp->FileObject;
201 PAFD_FCB FCB = FileObject->FsContext;
202 PAFD_SEND_INFO SendReq;
203 UINT TotalBytesCopied = 0, i, CopySize = 0,
204 SpaceAvail = 0, TotalBytesEncountered = 0;
205
206 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
207
208 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
209
210 FCB->EventsFired &= ~AFD_EVENT_SEND;
211
212 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
213 {
214 PAFD_SEND_INFO_UDP SendReq;
215 PTDI_CONNECTION_INFORMATION TargetAddress;
216
217 /* Check that the socket is bound */
218 if( FCB->State != SOCKET_STATE_BOUND )
219 return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL, Irp,
220 0, NULL );
221
222 if( !(SendReq = LockRequest( Irp, IrpSp )) )
223 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0,
224 NULL );
225
226 /* Must lock buffers before handing off user data */
227 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
228 SendReq->BufferCount,
229 NULL, NULL,
230 FALSE, FALSE );
231
232 if( !SendReq->BufferArray ) {
233 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
234 Irp, 0, NULL );
235 }
236
237 TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress );
238
239 if( TargetAddress ) {
240 SocketCalloutEnter( FCB );
241
242 Status = TdiSendDatagram
243 ( &FCB->SendIrp.InFlightRequest,
244 FCB->AddressFile.Object,
245 SendReq->BufferArray[0].buf,
246 SendReq->BufferArray[0].len,
247 TargetAddress,
248 &FCB->SendIrp.Iosb,
249 PacketSocketSendComplete,
250 FCB );
251
252 SocketCalloutLeave( FCB );
253
254 ExFreePool( TargetAddress );
255 } else Status = STATUS_NO_MEMORY;
256
257 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
258
259 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
260
261 return UnlockAndMaybeComplete( FCB, Status, Irp,
262 SendReq->BufferArray[0].len,
263 NULL );
264 }
265
266 if( !(SendReq = LockRequest( Irp, IrpSp )) )
267 return UnlockAndMaybeComplete
268 ( FCB, STATUS_NO_MEMORY, Irp, TotalBytesCopied, NULL );
269
270 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
271 SendReq->BufferCount,
272 NULL, NULL,
273 FALSE, FALSE );
274
275 if( !SendReq->BufferArray ) {
276 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
277 Irp, 0, NULL );
278 }
279
280 AFD_DbgPrint(MID_TRACE,("Socket state %d\n", FCB->State));
281
282 if( FCB->State != SOCKET_STATE_CONNECTED ) {
283 if( SendReq->AfdFlags & AFD_IMMEDIATE ) {
284 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
285 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
286 return UnlockAndMaybeComplete
287 ( FCB, STATUS_CANT_WAIT, Irp, 0, NULL );
288 } else {
289 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
290 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
291 }
292 }
293
294 AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %d\n",
295 FCB->Send.BytesUsed));
296
297 if( !FCB->Send.BytesUsed ) {
298 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
299
300 AFD_DbgPrint(MID_TRACE,("We can accept %d bytes\n",
301 SpaceAvail));
302
303 for( i = 0; FCB->Send.BytesUsed < FCB->Send.Size &&
304 i < SendReq->BufferCount; i++ ) {
305 CopySize = MIN( SpaceAvail,
306 SendReq->BufferArray[i].len );
307
308 TotalBytesEncountered += SendReq->BufferArray[i].len;
309
310 AFD_DbgPrint(MID_TRACE,("Copying Buffer %d, %x:%d to %x\n",
311 i,
312 SendReq->BufferArray[i].buf,
313 CopySize,
314 FCB->Send.Window + FCB->Send.BytesUsed));
315
316 RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
317 SendReq->BufferArray[i].buf,
318 CopySize );
319
320 FCB->Send.BytesUsed += CopySize;
321 TotalBytesCopied += CopySize;
322 SpaceAvail -= CopySize;
323 }
324
325 if( TotalBytesEncountered == 0 ) {
326 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
327
328 AFD_DbgPrint(MID_TRACE,("Empty send\n"));
329 return UnlockAndMaybeComplete
330 ( FCB, Status, Irp, TotalBytesCopied, NULL );
331 }
332
333 AFD_DbgPrint(MID_TRACE,("Completed %d bytes\n", TotalBytesCopied));
334
335 if( TotalBytesCopied > 0 ) {
336 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
337
338 FCB->SendIrp.InFlightRequest = (PVOID)1; /* Placeholder */
339
340 SocketCalloutEnter( FCB );
341
342 Status = TdiSend( &FCB->SendIrp.InFlightRequest,
343 FCB->Connection.Object,
344 0,
345 FCB->Send.Window,
346 FCB->Send.BytesUsed,
347 &FCB->SendIrp.Iosb,
348 SendComplete,
349 FCB );
350
351 SocketCalloutLeave( FCB );
352
353 if( Status == STATUS_PENDING )
354 Status = STATUS_SUCCESS;
355
356 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x (%d)\n",
357 Status, TotalBytesCopied));
358
359 return UnlockAndMaybeComplete
360 ( FCB, Status, Irp, TotalBytesCopied, NULL );
361 }
362 }
363
364 if( SendReq->AfdFlags & AFD_IMMEDIATE ) {
365 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
366 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
367 return UnlockAndMaybeComplete
368 ( FCB, STATUS_CANT_WAIT, Irp, 0, NULL );
369 } else {
370 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
371 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
372 }
373 }
374
375 NTSTATUS STDCALL
376 AfdPacketSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
377 PIO_STACK_LOCATION IrpSp) {
378 NTSTATUS Status = STATUS_SUCCESS;
379 PTDI_CONNECTION_INFORMATION TargetAddress;
380 PFILE_OBJECT FileObject = IrpSp->FileObject;
381 PAFD_FCB FCB = FileObject->FsContext;
382 PAFD_SEND_INFO_UDP SendReq;
383
384 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
385
386 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
387
388 FCB->EventsFired &= ~AFD_EVENT_SEND;
389 FCB->PollState &= ~AFD_EVENT_SEND;
390
391 /* Check that the socket is bound */
392 if( FCB->State != SOCKET_STATE_BOUND )
393 return UnlockAndMaybeComplete
394 ( FCB, STATUS_UNSUCCESSFUL, Irp, 0, NULL );
395 if( !(SendReq = LockRequest( Irp, IrpSp )) )
396 return UnlockAndMaybeComplete
397 ( FCB, STATUS_NO_MEMORY, Irp, 0, NULL );
398
399 AFD_DbgPrint
400 (MID_TRACE,("RemoteAddress #%d Type %d\n",
401 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress)->
402 TAAddressCount,
403 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress)->
404 Address[0].AddressType));
405
406 TdiBuildConnectionInfo( &TargetAddress,
407 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress) );
408
409 /* Check the size of the Address given ... */
410
411 if( TargetAddress ) {
412 SocketCalloutEnter( FCB );
413
414 Status = TdiSendDatagram
415 ( &FCB->SendIrp.InFlightRequest,
416 FCB->AddressFile.Object,
417 SendReq->BufferArray[0].buf,
418 SendReq->BufferArray[0].len,
419 TargetAddress,
420 &FCB->SendIrp.Iosb,
421 PacketSocketSendComplete,
422 FCB );
423
424 SocketCalloutLeave( FCB );
425
426 ExFreePool( TargetAddress );
427 } else Status = STATUS_NO_MEMORY;
428
429 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
430
431 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
432
433 return UnlockAndMaybeComplete
434 ( FCB, Status, Irp, SendReq->BufferArray[0].len, NULL );
435 }
436