16c65e4e658680ab143a37cf62c6c7f6bd9b05d7
[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( !SocketAcquireStateLock( FCB ) )
44 return STATUS_FILE_CLOSED;
45
46 FCB->SendIrp.InFlightRequest = NULL;
47 /* Request is not in flight any longer */
48
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 );
62 }
63 SocketStateUnlock( FCB );
64 return STATUS_FILE_CLOSED;
65 }
66
67 if( !NT_SUCCESS(Status) ) {
68 /* Complete all following send IRPs with error */
69
70 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
71 NextIrpEntry =
72 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
73 NextIrp =
74 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
75 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
76 SendReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
77
78 UnlockBuffers( SendReq->BufferArray,
79 SendReq->BufferCount,
80 FALSE );
81
82 NextIrp->IoStatus.Status = Status;
83 NextIrp->IoStatus.Information = 0;
84
85 if ( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
86 (void)IoSetCancelRoutine(NextIrp, NULL);
87 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
88 }
89
90 SocketStateUnlock( FCB );
91
92 return STATUS_SUCCESS;
93 }
94
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;
99
100 if( !FCB->Send.BytesUsed &&
101 !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
102 NextIrpEntry =
103 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
104 NextIrp =
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);
109
110 AFD_DbgPrint(MID_TRACE,("SendReq @ %x\n", SendReq));
111
112 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
113
114 for( i = 0; i < SendReq->BufferCount; i++ ) {
115 Map[i].BufferAddress =
116 MmMapLockedPages( Map[i].Mdl, KernelMode );
117
118 CopySize = MIN( SpaceAvail,
119 SendReq->BufferArray[i].len );
120
121 RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
122 Map[i].BufferAddress,
123 CopySize );
124
125 MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
126
127 FCB->Send.BytesUsed += CopySize;
128 TotalBytesCopied += CopySize;
129 SpaceAvail -= CopySize;
130 }
131 }
132
133 /* Some data is still waiting */
134 if( FCB->Send.BytesUsed ) {
135 FCB->PollState &= ~AFD_EVENT_SEND;
136
137 Status = TdiSend( &FCB->SendIrp.InFlightRequest,
138 FCB->Connection.Object,
139 0,
140 FCB->Send.Window,
141 FCB->Send.BytesUsed,
142 &FCB->SendIrp.Iosb,
143 SendComplete,
144 FCB );
145 } else {
146 FCB->PollState |= AFD_EVENT_SEND;
147 }
148
149 PollReeval( FCB->DeviceExt, FCB->FileObject );
150
151 if( TotalBytesCopied > 0 ) {
152 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
153
154 if( Status == STATUS_PENDING )
155 Status = STATUS_SUCCESS;
156
157 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
158
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",
162 NextIrp));
163 InsertHeadList( &FCB->PendingIrpList[FUNCTION_SEND],
164 &NextIrp->Tail.Overlay.ListEntry );
165 }
166
167 SocketStateUnlock( FCB );
168
169 return STATUS_SUCCESS;
170 }
171
172 static NTSTATUS NTAPI PacketSocketSendComplete
173 ( PDEVICE_OBJECT DeviceObject,
174 PIRP Irp,
175 PVOID Context ) {
176 PAFD_FCB FCB = (PAFD_FCB)Context;
177 PLIST_ENTRY NextIrpEntry;
178 PIRP NextIrp;
179
180 AFD_DbgPrint(MID_TRACE,("Called, status %x, %d bytes used\n",
181 Irp->IoStatus.Status,
182 Irp->IoStatus.Information));
183
184 if( !SocketAcquireStateLock( FCB ) )
185 return STATUS_FILE_CLOSED;
186
187 FCB->SendIrp.InFlightRequest = NULL;
188 /* Request is not in flight any longer */
189
190 FCB->PollState |= AFD_EVENT_SEND;
191 PollReeval( FCB->DeviceExt, FCB->FileObject );
192
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 );
203 }
204 SocketStateUnlock( FCB );
205 return STATUS_FILE_CLOSED;
206 }
207
208 SocketStateUnlock( FCB );
209
210 return STATUS_SUCCESS;
211 }
212
213 NTSTATUS NTAPI
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;
220 ULONG Information;
221 UINT TotalBytesCopied = 0, i, CopySize = 0,
222 SpaceAvail = 0, TotalBytesEncountered = 0;
223
224 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
225
226 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
227
228 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
229 {
230 PAFD_SEND_INFO_UDP SendReq;
231 PTDI_CONNECTION_INFORMATION TargetAddress;
232
233 /* Check that the socket is bound */
234 if( FCB->State != SOCKET_STATE_BOUND )
235 return UnlockAndMaybeComplete( FCB, STATUS_INVALID_PARAMETER, Irp,
236 0 );
237
238 if( !(SendReq = LockRequest( Irp, IrpSp )) )
239 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 );
240
241 /* Must lock buffers before handing off user data */
242 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
243 SendReq->BufferCount,
244 NULL, NULL,
245 FALSE, FALSE );
246
247 if( !SendReq->BufferArray ) {
248 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
249 Irp, 0 );
250 }
251
252 TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress );
253
254 if( TargetAddress ) {
255 Status = TdiSendDatagram
256 ( &FCB->SendIrp.InFlightRequest,
257 FCB->AddressFile.Object,
258 SendReq->BufferArray[0].buf,
259 SendReq->BufferArray[0].len,
260 TargetAddress,
261 &FCB->SendIrp.Iosb,
262 PacketSocketSendComplete,
263 FCB );
264
265 ExFreePool( TargetAddress );
266 } else Status = STATUS_NO_MEMORY;
267
268 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
269
270 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
271
272 /* Even if we were pended, we're done with the user buffer at this
273 * point. */
274 Information = SendReq->BufferArray[0].len;
275 UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
276 return UnlockAndMaybeComplete( FCB, Status, Irp, Information );
277 }
278
279 if( !(SendReq = LockRequest( Irp, IrpSp )) )
280 return UnlockAndMaybeComplete
281 ( FCB, STATUS_NO_MEMORY, Irp, TotalBytesCopied );
282
283 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
284 SendReq->BufferCount,
285 NULL, NULL,
286 FALSE, FALSE );
287
288 if( !SendReq->BufferArray ) {
289 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
290 Irp, 0 );
291 }
292
293 AFD_DbgPrint(MID_TRACE,("Socket state %d\n", FCB->State));
294
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 );
301 } else {
302 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
303 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
304 }
305 }
306
307 AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %d\n",
308 FCB->Send.BytesUsed));
309
310 if( !FCB->Send.BytesUsed ) {
311 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
312
313 AFD_DbgPrint(MID_TRACE,("We can accept %d bytes\n",
314 SpaceAvail));
315
316 for( i = 0; FCB->Send.BytesUsed < FCB->Send.Size &&
317 i < SendReq->BufferCount; i++ ) {
318 CopySize = MIN( SpaceAvail,
319 SendReq->BufferArray[i].len );
320
321 TotalBytesEncountered += SendReq->BufferArray[i].len;
322
323 AFD_DbgPrint(MID_TRACE,("Copying Buffer %d, %x:%d to %x\n",
324 i,
325 SendReq->BufferArray[i].buf,
326 CopySize,
327 FCB->Send.Window + FCB->Send.BytesUsed));
328
329 RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
330 SendReq->BufferArray[i].buf,
331 CopySize );
332
333 FCB->Send.BytesUsed += CopySize;
334 TotalBytesCopied += CopySize;
335 SpaceAvail -= CopySize;
336 }
337
338 if( TotalBytesEncountered == 0 ) {
339 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
340
341 AFD_DbgPrint(MID_TRACE,("Empty send\n"));
342 return UnlockAndMaybeComplete
343 ( FCB, Status, Irp, TotalBytesCopied );
344 }
345
346 AFD_DbgPrint(MID_TRACE,("Completed %d bytes\n", TotalBytesCopied));
347
348 if( TotalBytesCopied > 0 ) {
349 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
350
351 Status = TdiSend( &FCB->SendIrp.InFlightRequest,
352 FCB->Connection.Object,
353 0,
354 FCB->Send.Window,
355 FCB->Send.BytesUsed,
356 &FCB->SendIrp.Iosb,
357 SendComplete,
358 FCB );
359
360 if( Status == STATUS_PENDING )
361 Status = STATUS_SUCCESS;
362
363 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x (%d)\n",
364 Status, TotalBytesCopied));
365
366 return UnlockAndMaybeComplete
367 ( FCB, Status, Irp, TotalBytesCopied );
368 }
369 }
370
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 );
376 } else {
377 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
378 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
379 }
380 }
381
382 NTSTATUS NTAPI
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;
390 ULONG Information;
391
392 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
393
394 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
395
396 FCB->PollState &= ~AFD_EVENT_SEND;
397
398 PollReeval( FCB->DeviceExt, FCB->FileObject );
399
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 );
407
408 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
409 SendReq->BufferCount,
410 NULL, NULL,
411 FALSE, FALSE );
412
413 if( !SendReq->BufferArray )
414 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
415 Irp, 0 );
416
417 AFD_DbgPrint
418 (MID_TRACE,("RemoteAddress #%d Type %d\n",
419 ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)->
420 TAAddressCount,
421 ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)->
422 Address[0].AddressType));
423
424 TdiBuildConnectionInfo( &TargetAddress,
425 ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress) );
426
427 /* Check the size of the Address given ... */
428
429 if( TargetAddress ) {
430 Status = TdiSendDatagram
431 ( &FCB->SendIrp.InFlightRequest,
432 FCB->AddressFile.Object,
433 SendReq->BufferArray[0].buf,
434 SendReq->BufferArray[0].len,
435 TargetAddress,
436 &FCB->SendIrp.Iosb,
437 PacketSocketSendComplete,
438 FCB );
439
440 ExFreePool( TargetAddress );
441 } else Status = STATUS_NO_MEMORY;
442
443 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
444
445 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
446
447 /* Even if we were pended, we're done with the user buffer at this
448 * point. */
449 Information = SendReq->BufferArray[0].len;
450 UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
451 return UnlockAndMaybeComplete( FCB, Status, Irp, Information );
452 }
453