Sync with trunk r63192.
[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
11 #include "afd.h"
12
13 static IO_COMPLETION_ROUTINE SendComplete;
14 static NTSTATUS NTAPI SendComplete
15 ( PDEVICE_OBJECT DeviceObject,
16 PIRP Irp,
17 PVOID Context ) {
18 NTSTATUS Status = Irp->IoStatus.Status;
19 PAFD_FCB FCB = (PAFD_FCB)Context;
20 PLIST_ENTRY NextIrpEntry;
21 PIRP NextIrp = NULL;
22 PIO_STACK_LOCATION NextIrpSp;
23 PAFD_SEND_INFO SendReq = NULL;
24 PAFD_MAPBUF Map;
25 UINT TotalBytesCopied = 0, TotalBytesProcessed = 0, SpaceAvail, i;
26 UINT SendLength, BytesCopied;
27 BOOLEAN HaltSendQueue;
28
29 UNREFERENCED_PARAMETER(DeviceObject);
30
31 /*
32 * The Irp parameter passed in is the IRP of the stream between AFD and
33 * TDI driver. It's not very usefull to us. We need the IRPs of the stream
34 * between usermode and AFD. Those are chained from
35 * FCB->PendingIrpList[FUNCTION_SEND] and you'll see them in the code
36 * below as "NextIrp" ('cause they are the next usermode IRP to be
37 * processed).
38 */
39
40 AFD_DbgPrint(MID_TRACE,("Called, status %x, %u bytes used\n",
41 Irp->IoStatus.Status,
42 Irp->IoStatus.Information));
43
44 if( !SocketAcquireStateLock( FCB ) )
45 return STATUS_FILE_CLOSED;
46
47 ASSERT(FCB->SendIrp.InFlightRequest == Irp);
48 FCB->SendIrp.InFlightRequest = NULL;
49 /* Request is not in flight any longer */
50
51 if( FCB->State == SOCKET_STATE_CLOSED ) {
52 /* Cleanup our IRP queue because the FCB is being destroyed */
53 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
54 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
55 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
56 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
57 SendReq = GetLockedData(NextIrp, NextIrpSp);
58 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
59 NextIrp->IoStatus.Information = 0;
60 UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
61 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
62 (void)IoSetCancelRoutine(NextIrp, NULL);
63 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
64 }
65
66 RetryDisconnectCompletion(FCB);
67
68 SocketStateUnlock( FCB );
69 return STATUS_FILE_CLOSED;
70 }
71
72 if( !NT_SUCCESS(Status) ) {
73 /* Complete all following send IRPs with error */
74
75 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
76 NextIrpEntry =
77 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
78 NextIrp =
79 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
80 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
81 SendReq = GetLockedData(NextIrp, NextIrpSp);
82
83 UnlockBuffers( SendReq->BufferArray,
84 SendReq->BufferCount,
85 FALSE );
86
87 NextIrp->IoStatus.Status = Status;
88 NextIrp->IoStatus.Information = 0;
89
90 if ( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
91 (void)IoSetCancelRoutine(NextIrp, NULL);
92 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
93 }
94
95 RetryDisconnectCompletion(FCB);
96
97 SocketStateUnlock( FCB );
98
99 return STATUS_SUCCESS;
100 }
101
102 RtlMoveMemory( FCB->Send.Window,
103 FCB->Send.Window + Irp->IoStatus.Information,
104 FCB->Send.BytesUsed - Irp->IoStatus.Information );
105
106 TotalBytesProcessed = 0;
107 SendLength = Irp->IoStatus.Information;
108 HaltSendQueue = FALSE;
109 while (!IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]) && SendLength > 0) {
110 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
111 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
112 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
113 SendReq = GetLockedData(NextIrp, NextIrpSp);
114 Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount);
115
116 TotalBytesCopied = (ULONG_PTR)NextIrp->Tail.Overlay.DriverContext[3];
117 ASSERT(TotalBytesCopied != 0);
118
119 /* If we didn't get enough, keep waiting */
120 if (TotalBytesCopied > SendLength)
121 {
122 /* Update the bytes left to copy */
123 TotalBytesCopied -= SendLength;
124 NextIrp->Tail.Overlay.DriverContext[3] = (PVOID)TotalBytesCopied;
125
126 /* Update the state variables */
127 FCB->Send.BytesUsed -= SendLength;
128 TotalBytesProcessed += SendLength;
129 SendLength = 0;
130
131 /* Pend the IRP */
132 InsertHeadList(&FCB->PendingIrpList[FUNCTION_SEND],
133 &NextIrp->Tail.Overlay.ListEntry);
134 HaltSendQueue = TRUE;
135 break;
136 }
137
138 ASSERT(NextIrp->IoStatus.Information != 0);
139
140 NextIrp->IoStatus.Status = Irp->IoStatus.Status;
141
142 FCB->Send.BytesUsed -= TotalBytesCopied;
143 TotalBytesProcessed += TotalBytesCopied;
144 SendLength -= TotalBytesCopied;
145
146 (void)IoSetCancelRoutine(NextIrp, NULL);
147
148 UnlockBuffers( SendReq->BufferArray,
149 SendReq->BufferCount,
150 FALSE );
151
152 if (NextIrp->MdlAddress) UnlockRequest(NextIrp, NextIrpSp);
153
154 IoCompleteRequest(NextIrp, IO_NETWORK_INCREMENT);
155 }
156
157 ASSERT(SendLength == 0);
158
159 if ( !HaltSendQueue && !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
160 NextIrpEntry = FCB->PendingIrpList[FUNCTION_SEND].Flink;
161 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
162 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
163 SendReq = GetLockedData(NextIrp, NextIrpSp);
164 Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount);
165
166 AFD_DbgPrint(MID_TRACE,("SendReq @ %p\n", SendReq));
167
168 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
169 TotalBytesCopied = 0;
170
171 /* Count the total transfer size */
172 SendLength = 0;
173 for (i = 0; i < SendReq->BufferCount; i++)
174 {
175 SendLength += SendReq->BufferArray[i].len;
176 }
177
178 /* Make sure we've got the space */
179 if (SendLength > SpaceAvail)
180 {
181 /* Blocking sockets have to wait here */
182 if (SendLength <= FCB->Send.Size && !((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking)))
183 {
184 FCB->PollState &= ~AFD_EVENT_SEND;
185
186 NextIrp = NULL;
187 }
188
189 /* Check if we can send anything */
190 if (SpaceAvail == 0)
191 {
192 FCB->PollState &= ~AFD_EVENT_SEND;
193
194 /* We should never be non-overlapped and get to this point */
195 ASSERT(SendReq->AfdFlags & AFD_OVERLAPPED);
196
197 NextIrp = NULL;
198 }
199 }
200
201 if (NextIrp != NULL)
202 {
203 for( i = 0; i < SendReq->BufferCount; i++ ) {
204 BytesCopied = MIN(SendReq->BufferArray[i].len, SpaceAvail);
205
206 Map[i].BufferAddress =
207 MmMapLockedPages( Map[i].Mdl, KernelMode );
208
209 RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
210 Map[i].BufferAddress,
211 BytesCopied );
212
213 MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
214
215 TotalBytesCopied += BytesCopied;
216 SpaceAvail -= BytesCopied;
217 FCB->Send.BytesUsed += BytesCopied;
218 }
219
220 NextIrp->IoStatus.Information = TotalBytesCopied;
221 NextIrp->Tail.Overlay.DriverContext[3] = (PVOID)NextIrp->IoStatus.Information;
222 }
223 }
224
225 if (FCB->Send.Size - FCB->Send.BytesUsed != 0 && !FCB->SendClosed &&
226 IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]))
227 {
228 FCB->PollState |= AFD_EVENT_SEND;
229 FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
230 PollReeval( FCB->DeviceExt, FCB->FileObject );
231 }
232 else
233 {
234 FCB->PollState &= ~AFD_EVENT_SEND;
235 }
236
237
238 /* Some data is still waiting */
239 if( FCB->Send.BytesUsed )
240 {
241 Status = TdiSend( &FCB->SendIrp.InFlightRequest,
242 FCB->Connection.Object,
243 0,
244 FCB->Send.Window,
245 FCB->Send.BytesUsed,
246 &FCB->SendIrp.Iosb,
247 SendComplete,
248 FCB );
249 }
250 else
251 {
252 /* Nothing is waiting so try to complete a pending disconnect */
253 RetryDisconnectCompletion(FCB);
254 }
255
256 SocketStateUnlock( FCB );
257
258 return STATUS_SUCCESS;
259 }
260
261 static IO_COMPLETION_ROUTINE PacketSocketSendComplete;
262 static NTSTATUS NTAPI PacketSocketSendComplete
263 ( PDEVICE_OBJECT DeviceObject,
264 PIRP Irp,
265 PVOID Context ) {
266 PAFD_FCB FCB = (PAFD_FCB)Context;
267 PLIST_ENTRY NextIrpEntry;
268 PIRP NextIrp;
269 PAFD_SEND_INFO SendReq;
270
271 UNREFERENCED_PARAMETER(DeviceObject);
272
273 AFD_DbgPrint(MID_TRACE,("Called, status %x, %u bytes used\n",
274 Irp->IoStatus.Status,
275 Irp->IoStatus.Information));
276
277 if( !SocketAcquireStateLock( FCB ) )
278 return STATUS_FILE_CLOSED;
279
280 ASSERT(FCB->SendIrp.InFlightRequest == Irp);
281 FCB->SendIrp.InFlightRequest = NULL;
282 /* Request is not in flight any longer */
283
284 if( FCB->State == SOCKET_STATE_CLOSED ) {
285 /* Cleanup our IRP queue because the FCB is being destroyed */
286 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
287 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
288 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
289 SendReq = GetLockedData(NextIrp, IoGetCurrentIrpStackLocation(NextIrp));
290 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
291 NextIrp->IoStatus.Information = 0;
292 (void)IoSetCancelRoutine(NextIrp, NULL);
293 UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
294 UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
295 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
296 }
297 SocketStateUnlock( FCB );
298 return STATUS_FILE_CLOSED;
299 }
300
301 ASSERT(!IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]));
302
303 /* TDI spec guarantees FIFO ordering on IRPs */
304 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
305 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
306
307 SendReq = GetLockedData(NextIrp, IoGetCurrentIrpStackLocation(NextIrp));
308
309 NextIrp->IoStatus.Status = Irp->IoStatus.Status;
310 NextIrp->IoStatus.Information = Irp->IoStatus.Information;
311
312 (void)IoSetCancelRoutine(NextIrp, NULL);
313
314 UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
315
316 UnlockRequest(NextIrp, IoGetCurrentIrpStackLocation(NextIrp));
317
318 IoCompleteRequest(NextIrp, IO_NETWORK_INCREMENT);
319
320 FCB->PollState |= AFD_EVENT_SEND;
321 FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
322 PollReeval(FCB->DeviceExt, FCB->FileObject);
323
324 SocketStateUnlock(FCB);
325
326 return STATUS_SUCCESS;
327 }
328
329 NTSTATUS NTAPI
330 AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
331 PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
332 NTSTATUS Status = STATUS_SUCCESS;
333 PFILE_OBJECT FileObject = IrpSp->FileObject;
334 PAFD_FCB FCB = FileObject->FsContext;
335 PAFD_SEND_INFO SendReq;
336 UINT TotalBytesCopied = 0, i, SpaceAvail = 0, BytesCopied, SendLength;
337 KPROCESSOR_MODE LockMode;
338
339 UNREFERENCED_PARAMETER(DeviceObject);
340 UNREFERENCED_PARAMETER(Short);
341
342 AFD_DbgPrint(MID_TRACE,("Called on %p\n", FCB));
343
344 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
345
346 FCB->EventSelectDisabled &= ~AFD_EVENT_SEND;
347
348 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
349 {
350 PAFD_SEND_INFO_UDP SendReq;
351 PTDI_CONNECTION_INFORMATION TargetAddress;
352
353 /* Check that the socket is bound */
354 if( FCB->State != SOCKET_STATE_BOUND || !FCB->RemoteAddress )
355 {
356 AFD_DbgPrint(MIN_TRACE,("Invalid parameter\n"));
357 return UnlockAndMaybeComplete( FCB, STATUS_INVALID_PARAMETER, Irp,
358 0 );
359 }
360
361 if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) )
362 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 );
363
364 /* Must lock buffers before handing off user data */
365 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
366 SendReq->BufferCount,
367 NULL, NULL,
368 FALSE, FALSE, LockMode );
369
370 if( !SendReq->BufferArray ) {
371 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
372 Irp, 0 );
373 }
374
375 Status = TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress );
376
377 if( NT_SUCCESS(Status) ) {
378 FCB->PollState &= ~AFD_EVENT_SEND;
379
380 Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND);
381 if (Status == STATUS_PENDING)
382 {
383 TdiSendDatagram(&FCB->SendIrp.InFlightRequest,
384 FCB->AddressFile.Object,
385 SendReq->BufferArray[0].buf,
386 SendReq->BufferArray[0].len,
387 TargetAddress,
388 &FCB->SendIrp.Iosb,
389 PacketSocketSendComplete,
390 FCB);
391 }
392
393 ExFreePool( TargetAddress );
394
395 SocketStateUnlock(FCB);
396
397 return STATUS_PENDING;
398 }
399 else
400 {
401 UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
402 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
403 }
404 }
405
406 if (FCB->PollState & AFD_EVENT_CLOSE)
407 {
408 AFD_DbgPrint(MIN_TRACE,("Connection reset by remote peer\n"));
409
410 /* This is an unexpected remote disconnect */
411 return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0);
412 }
413
414 if (FCB->PollState & AFD_EVENT_ABORT)
415 {
416 AFD_DbgPrint(MIN_TRACE,("Connection aborted\n"));
417
418 /* This is an abortive socket closure on our side */
419 return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0);
420 }
421
422 if (FCB->SendClosed)
423 {
424 AFD_DbgPrint(MIN_TRACE,("No more sends\n"));
425
426 /* This is a graceful send closure */
427 return UnlockAndMaybeComplete(FCB, STATUS_FILE_CLOSED, Irp, 0);
428 }
429
430 if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) )
431 return UnlockAndMaybeComplete
432 ( FCB, STATUS_NO_MEMORY, Irp, 0 );
433
434 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
435 SendReq->BufferCount,
436 NULL, NULL,
437 FALSE, FALSE, LockMode );
438
439 if( !SendReq->BufferArray ) {
440 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
441 Irp, 0 );
442 }
443
444 AFD_DbgPrint(MID_TRACE,("Socket state %u\n", FCB->State));
445
446 if( FCB->State != SOCKET_STATE_CONNECTED ) {
447 if (!(SendReq->AfdFlags & AFD_OVERLAPPED) &&
448 ((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking))) {
449 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
450 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
451 return UnlockAndMaybeComplete( FCB, STATUS_CANT_WAIT, Irp, 0 );
452 } else {
453 AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
454 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
455 }
456 }
457
458 AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %u\n",
459 FCB->Send.BytesUsed));
460
461 SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
462
463 AFD_DbgPrint(MID_TRACE,("We can accept %u bytes\n",
464 SpaceAvail));
465
466 /* Count the total transfer size */
467 SendLength = 0;
468 for (i = 0; i < SendReq->BufferCount; i++)
469 {
470 SendLength += SendReq->BufferArray[i].len;
471 }
472
473 /* Make sure we've got the space */
474 if (SendLength > SpaceAvail)
475 {
476 /* Blocking sockets have to wait here */
477 if (SendLength <= FCB->Send.Size && !((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking)))
478 {
479 FCB->PollState &= ~AFD_EVENT_SEND;
480 return LeaveIrpUntilLater(FCB, Irp, FUNCTION_SEND);
481 }
482
483 /* Check if we can send anything */
484 if (SpaceAvail == 0)
485 {
486 FCB->PollState &= ~AFD_EVENT_SEND;
487
488 /* Non-overlapped sockets will fail if we can send nothing */
489 if (!(SendReq->AfdFlags & AFD_OVERLAPPED))
490 {
491 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
492 return UnlockAndMaybeComplete( FCB, STATUS_CANT_WAIT, Irp, 0 );
493 }
494 else
495 {
496 /* Overlapped sockets just pend */
497 return LeaveIrpUntilLater(FCB, Irp, FUNCTION_SEND);
498 }
499 }
500 }
501
502 for ( i = 0; SpaceAvail > 0 && i < SendReq->BufferCount; i++ )
503 {
504 BytesCopied = MIN(SendReq->BufferArray[i].len, SpaceAvail);
505
506 AFD_DbgPrint(MID_TRACE,("Copying Buffer %u, %p:%u to %p\n",
507 i,
508 SendReq->BufferArray[i].buf,
509 BytesCopied,
510 FCB->Send.Window + FCB->Send.BytesUsed));
511
512 RtlCopyMemory(FCB->Send.Window + FCB->Send.BytesUsed,
513 SendReq->BufferArray[i].buf,
514 BytesCopied);
515
516 TotalBytesCopied += BytesCopied;
517 SpaceAvail -= BytesCopied;
518 FCB->Send.BytesUsed += BytesCopied;
519 }
520
521 Irp->IoStatus.Information = TotalBytesCopied;
522
523 if( TotalBytesCopied == 0 ) {
524 AFD_DbgPrint(MID_TRACE,("Empty send\n"));
525 UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
526 return UnlockAndMaybeComplete
527 ( FCB, STATUS_SUCCESS, Irp, TotalBytesCopied );
528 }
529
530 if (SpaceAvail)
531 {
532 FCB->PollState |= AFD_EVENT_SEND;
533 FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
534 PollReeval( FCB->DeviceExt, FCB->FileObject );
535 }
536 else
537 {
538 FCB->PollState &= ~AFD_EVENT_SEND;
539 }
540
541 /* We use the IRP tail for some temporary storage here */
542 Irp->Tail.Overlay.DriverContext[3] = (PVOID)Irp->IoStatus.Information;
543
544 Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND);
545 if (Status == STATUS_PENDING && !FCB->SendIrp.InFlightRequest)
546 {
547 TdiSend(&FCB->SendIrp.InFlightRequest,
548 FCB->Connection.Object,
549 0,
550 FCB->Send.Window,
551 FCB->Send.BytesUsed,
552 &FCB->SendIrp.Iosb,
553 SendComplete,
554 FCB);
555 }
556
557 SocketStateUnlock(FCB);
558
559 return STATUS_PENDING;
560 }
561
562 NTSTATUS NTAPI
563 AfdPacketSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
564 PIO_STACK_LOCATION IrpSp) {
565 NTSTATUS Status = STATUS_SUCCESS;
566 PTDI_CONNECTION_INFORMATION TargetAddress;
567 PFILE_OBJECT FileObject = IrpSp->FileObject;
568 PAFD_FCB FCB = FileObject->FsContext;
569 PAFD_SEND_INFO_UDP SendReq;
570 KPROCESSOR_MODE LockMode;
571
572 UNREFERENCED_PARAMETER(DeviceObject);
573
574 AFD_DbgPrint(MID_TRACE,("Called on %p\n", FCB));
575
576 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
577
578 FCB->EventSelectDisabled &= ~AFD_EVENT_SEND;
579
580 /* Check that the socket is bound */
581 if( FCB->State != SOCKET_STATE_BOUND &&
582 FCB->State != SOCKET_STATE_CREATED)
583 {
584 AFD_DbgPrint(MIN_TRACE,("Invalid socket state\n"));
585 return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
586 }
587
588 if (FCB->SendClosed)
589 {
590 AFD_DbgPrint(MIN_TRACE,("No more sends\n"));
591 return UnlockAndMaybeComplete(FCB, STATUS_FILE_CLOSED, Irp, 0);
592 }
593
594 if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) )
595 return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
596
597 if (FCB->State == SOCKET_STATE_CREATED)
598 {
599 if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress );
600 FCB->LocalAddress =
601 TaBuildNullTransportAddress( ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)->
602 Address[0].AddressType );
603
604 if( FCB->LocalAddress ) {
605 Status = WarmSocketForBind( FCB, AFD_SHARE_WILDCARD );
606
607 if( NT_SUCCESS(Status) )
608 FCB->State = SOCKET_STATE_BOUND;
609 else
610 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
611 } else
612 return UnlockAndMaybeComplete
613 ( FCB, STATUS_NO_MEMORY, Irp, 0 );
614 }
615
616 SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
617 SendReq->BufferCount,
618 NULL, NULL,
619 FALSE, FALSE, LockMode );
620
621 if( !SendReq->BufferArray )
622 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
623 Irp, 0 );
624
625 AFD_DbgPrint
626 (MID_TRACE,("RemoteAddress #%d Type %u\n",
627 ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)->
628 TAAddressCount,
629 ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)->
630 Address[0].AddressType));
631
632 Status = TdiBuildConnectionInfo( &TargetAddress,
633 ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress) );
634
635 /* Check the size of the Address given ... */
636
637 if( NT_SUCCESS(Status) ) {
638 FCB->PollState &= ~AFD_EVENT_SEND;
639
640 Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND);
641 if (Status == STATUS_PENDING)
642 {
643 TdiSendDatagram(&FCB->SendIrp.InFlightRequest,
644 FCB->AddressFile.Object,
645 SendReq->BufferArray[0].buf,
646 SendReq->BufferArray[0].len,
647 TargetAddress,
648 &FCB->SendIrp.Iosb,
649 PacketSocketSendComplete,
650 FCB);
651 }
652
653 ExFreePool(TargetAddress);
654
655 SocketStateUnlock(FCB);
656
657 return STATUS_PENDING;
658 }
659 else
660 {
661 UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
662 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
663 }
664 }