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