Create a branch for network fixes.
[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 FCB->SendIrp.InFlightRequest = NULL;
45 return STATUS_SUCCESS;
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 DestroySocket( FCB );
56 return STATUS_SUCCESS;
57 }
58
59 if( !NT_SUCCESS(Status) ) {
60 /* Complete all following send IRPs with error */
61
62 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
63 NextIrpEntry =
64 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
65 NextIrp =
66 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
67 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
68 SendReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
69
70 UnlockBuffers( SendReq->BufferArray,
71 SendReq->BufferCount,
72 FALSE );
73
74 NextIrp->IoStatus.Status = Status;
75 NextIrp->IoStatus.Information = 0;
76
77 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
78 }
79
80 SocketStateUnlock( FCB );
81
82 return STATUS_SUCCESS;
83 }
84
85 RtlMoveMemory( FCB->Send.Window,
86 FCB->Send.Window + FCB->Send.BytesUsed,
87 FCB->Send.BytesUsed - Irp->IoStatus.Information );
88 FCB->Send.BytesUsed -= Irp->IoStatus.Information;
89
90 if( !FCB->Send.BytesUsed &&
91 !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) &&
92 NT_SUCCESS(Status) ) {
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, TRUE );
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 FCB->SendIrp.InFlightRequest = NULL;
179 return STATUS_SUCCESS;
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 if( FCB->State == SOCKET_STATE_CLOSED ) {
192 SocketStateUnlock( FCB );
193 DestroySocket( FCB );
194 return STATUS_SUCCESS;
195 }
196
197 SocketStateUnlock( FCB );
198
199 return STATUS_SUCCESS;
200 }
201
202 NTSTATUS STDCALL
203 AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
204 PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
205 NTSTATUS Status = STATUS_SUCCESS;
206 PFILE_OBJECT FileObject = IrpSp->FileObject;
207 PAFD_FCB FCB = FileObject->FsContext;
208 PAFD_SEND_INFO SendReq;
209 UINT TotalBytesCopied = 0, i, CopySize = 0,
210 SpaceAvail = 0, TotalBytesEncountered = 0;
211
212 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
213
214 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
215
216 FCB->EventsFired &= ~AFD_EVENT_SEND;
217
218 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
219 {
220 PAFD_SEND_INFO_UDP SendReq;
221 PTDI_CONNECTION_INFORMATION TargetAddress;
222
223 /* Check that the socket is bound */
224 if( FCB->State != SOCKET_STATE_BOUND )
225 return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL, Irp,
226 0, NULL, FALSE );
227
228 if( !(SendReq = LockRequest( Irp, IrpSp )) )
229 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0,
230 NULL, FALSE );
231
232 /* Must lock buffers before handing off user data */
233 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
234 SendReq->BufferCount,
235 NULL, NULL,
236 FALSE, FALSE );
237
238 TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress );
239
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
256 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
257
258 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
259
260 return UnlockAndMaybeComplete( FCB, Status, Irp,
261 SendReq->BufferArray[0].len,
262 NULL, TRUE );
263 }
264
265 if( !(SendReq = LockRequest( Irp, IrpSp )) )
266 return UnlockAndMaybeComplete
267 ( FCB, STATUS_NO_MEMORY, Irp, TotalBytesCopied, NULL, FALSE );
268
269 AFD_DbgPrint(MID_TRACE,("Socket state %d\n", FCB->State));
270
271 if( FCB->State != SOCKET_STATE_CONNECTED ) {
272 if( SendReq->AfdFlags & AFD_IMMEDIATE ) {
273 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
274 return UnlockAndMaybeComplete
275 ( FCB, STATUS_CANT_WAIT, Irp, 0, NULL, TRUE );
276 } else {
277 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
278 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
279 }
280 }
281
282 AFD_DbgPrint(MID_TRACE,("We already have %d bytes waiting.\n",
283 FCB->Send.BytesUsed));
284
285 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
286 SendReq->BufferCount,
287 NULL, NULL,
288 FALSE, FALSE );
289
290 AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %d\n",
291 FCB->Send.BytesUsed));
292
293 if( !FCB->Send.BytesUsed ) {
294 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
295
296 AFD_DbgPrint(MID_TRACE,("We can accept %d bytes\n",
297 SpaceAvail));
298
299 for( i = 0; FCB->Send.BytesUsed < FCB->Send.Size &&
300 i < SendReq->BufferCount; i++ ) {
301 CopySize = MIN( SpaceAvail,
302 SendReq->BufferArray[i].len );
303
304 TotalBytesEncountered += SendReq->BufferArray[i].len;
305
306 AFD_DbgPrint(MID_TRACE,("Copying Buffer %d, %x:%d to %x\n",
307 i,
308 SendReq->BufferArray[i].buf,
309 CopySize,
310 FCB->Send.Window + FCB->Send.BytesUsed));
311
312 RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
313 SendReq->BufferArray[i].buf,
314 CopySize );
315
316 FCB->Send.BytesUsed += CopySize;
317 TotalBytesCopied += CopySize;
318 SpaceAvail -= CopySize;
319 }
320
321 if( TotalBytesEncountered == 0 ) {
322 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
323
324 AFD_DbgPrint(MID_TRACE,("Empty send\n"));
325 return UnlockAndMaybeComplete
326 ( FCB, Status, Irp, TotalBytesCopied, NULL, TRUE );
327 }
328
329 AFD_DbgPrint(MID_TRACE,("Completed %d bytes\n", TotalBytesCopied));
330
331 if( TotalBytesCopied > 0 ) {
332 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
333
334 FCB->SendIrp.InFlightRequest = (PVOID)1; /* Placeholder */
335
336 SocketCalloutEnter( FCB );
337
338 Status = TdiSend( &FCB->SendIrp.InFlightRequest,
339 FCB->Connection.Object,
340 0,
341 FCB->Send.Window,
342 FCB->Send.BytesUsed,
343 &FCB->SendIrp.Iosb,
344 SendComplete,
345 FCB );
346
347 SocketCalloutLeave( FCB );
348
349 if( Status == STATUS_PENDING )
350 Status = STATUS_SUCCESS;
351
352 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x (%d)\n",
353 Status, TotalBytesCopied));
354
355 return UnlockAndMaybeComplete
356 ( FCB, Status, Irp, TotalBytesCopied, NULL, TRUE );
357 }
358 }
359
360 if( SendReq->AfdFlags & AFD_IMMEDIATE ) {
361 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
362 return UnlockAndMaybeComplete
363 ( FCB, STATUS_CANT_WAIT, Irp, 0, NULL, TRUE );
364 } else {
365 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
366 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
367 }
368 }
369
370 NTSTATUS STDCALL
371 AfdPacketSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
372 PIO_STACK_LOCATION IrpSp) {
373 NTSTATUS Status = STATUS_SUCCESS;
374 PTDI_CONNECTION_INFORMATION TargetAddress;
375 PFILE_OBJECT FileObject = IrpSp->FileObject;
376 PAFD_FCB FCB = FileObject->FsContext;
377 PAFD_SEND_INFO_UDP SendReq;
378
379 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
380
381 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
382
383 FCB->EventsFired &= ~AFD_EVENT_SEND;
384 FCB->PollState &= ~AFD_EVENT_SEND;
385
386 /* Check that the socket is bound */
387 if( FCB->State != SOCKET_STATE_BOUND )
388 return UnlockAndMaybeComplete
389 ( FCB, STATUS_UNSUCCESSFUL, Irp, 0, NULL, FALSE );
390 if( !(SendReq = LockRequest( Irp, IrpSp )) )
391 return UnlockAndMaybeComplete
392 ( FCB, STATUS_NO_MEMORY, Irp, 0, NULL, FALSE );
393
394 AFD_DbgPrint
395 (MID_TRACE,("RemoteAddress #%d Type %d\n",
396 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress)->
397 TAAddressCount,
398 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress)->
399 Address[0].AddressType));
400
401 TdiBuildConnectionInfo( &TargetAddress,
402 ((PTRANSPORT_ADDRESS)SendReq->RemoteAddress) );
403
404 /* Check the size of the Address given ... */
405
406 if( TargetAddress ) {
407 SocketCalloutEnter( FCB );
408
409 Status = TdiSendDatagram
410 ( &FCB->SendIrp.InFlightRequest,
411 FCB->AddressFile.Object,
412 SendReq->BufferArray[0].buf,
413 SendReq->BufferArray[0].len,
414 TargetAddress,
415 &FCB->SendIrp.Iosb,
416 PacketSocketSendComplete,
417 FCB );
418
419 SocketCalloutLeave( FCB );
420
421 ExFreePool( TargetAddress );
422 } else Status = STATUS_NO_MEMORY;
423
424 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
425
426 AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
427
428 return UnlockAndMaybeComplete
429 ( FCB, Status, Irp, SendReq->BufferArray[0].len, NULL, TRUE );
430 }
431