039a8ec9e02ebfe9d68b03b8205339b8f505c771
[reactos.git] / reactos / drivers / network / afd / afd / read.c
1 /* $Id$
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/read.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
7 * UPDATE HISTORY:
8 * 20040708 Created
9 *
10 * Improve buffering code
11 *
12 * We're keeping data receiving in one of two states:
13 * A) Some data available in the FCB
14 * FCB->Recv.BytesUsed != FCB->Recv.Content
15 * FCB->ReceiveIrp.InFlightRequest == NULL
16 * AFD_EVENT_RECEIVE set in FCB->PollState
17 * B) No data available in the FCB
18 * FCB->Recv.BytesUsed == FCB->Recv.Content (== 0)
19 * FCB->RecieveIrp.InFlightRequest != NULL
20 * AFD_EVENT_RECEIVED not set in FCB->PollState
21 * So basically we either have data available or a TDI receive
22 * in flight.
23 */
24 #include "afd.h"
25 #include "tdi_proto.h"
26 #include "tdiconn.h"
27 #include "debug.h"
28
29 static BOOLEAN CantReadMore( PAFD_FCB FCB ) {
30 UINT BytesAvailable = FCB->Recv.Content - FCB->Recv.BytesUsed;
31
32 return !BytesAvailable &&
33 (FCB->PollState & (AFD_EVENT_CLOSE | AFD_EVENT_DISCONNECT));
34 }
35
36 static VOID HandleEOFOnIrp( PAFD_FCB FCB, NTSTATUS Status, UINT Information ) {
37 if( Status == STATUS_SUCCESS && Information == 0 ) {
38 AFD_DbgPrint(MID_TRACE,("Looks like an EOF\n"));
39 FCB->PollState |= AFD_EVENT_DISCONNECT;
40 PollReeval( FCB->DeviceExt, FCB->FileObject );
41 }
42 }
43
44 static NTSTATUS TryToSatisfyRecvRequestFromBuffer( PAFD_FCB FCB,
45 PAFD_RECV_INFO RecvReq,
46 PUINT TotalBytesCopied ) {
47 UINT i, BytesToCopy = 0,
48 BytesAvailable =
49 FCB->Recv.Content - FCB->Recv.BytesUsed;
50 PAFD_MAPBUF Map;
51 NTSTATUS Status;
52 *TotalBytesCopied = 0;
53
54
55 AFD_DbgPrint(MID_TRACE,("Called, BytesAvailable = %d\n",
56 BytesAvailable));
57
58 if( CantReadMore(FCB) ) return STATUS_SUCCESS;
59 if( !BytesAvailable ) return STATUS_PENDING;
60
61 Map = (PAFD_MAPBUF)(RecvReq->BufferArray + RecvReq->BufferCount);
62
63 AFD_DbgPrint(MID_TRACE,("Buffer Count: %d @ %x\n",
64 RecvReq->BufferCount,
65 RecvReq->BufferArray));
66 for( i = 0;
67 RecvReq->BufferArray &&
68 BytesAvailable &&
69 i < RecvReq->BufferCount;
70 i++ ) {
71 BytesToCopy =
72 MIN( RecvReq->BufferArray[i].len, BytesAvailable );
73
74 if( Map[i].Mdl ) {
75 Map[i].BufferAddress = MmMapLockedPages( Map[i].Mdl, KernelMode );
76
77 AFD_DbgPrint(MID_TRACE,("Buffer %d: %x:%d\n",
78 i,
79 Map[i].BufferAddress,
80 BytesToCopy));
81
82 RtlCopyMemory( Map[i].BufferAddress,
83 FCB->Recv.Window + FCB->Recv.BytesUsed,
84 BytesToCopy );
85
86 MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
87
88 FCB->Recv.BytesUsed += BytesToCopy;
89 *TotalBytesCopied += BytesToCopy;
90 BytesAvailable -= BytesToCopy;
91 }
92 }
93
94 /* If there's nothing left in our buffer start a new request */
95 if( FCB->Recv.BytesUsed == FCB->Recv.Content ) {
96 FCB->Recv.BytesUsed = FCB->Recv.Content = 0;
97 FCB->PollState &= ~AFD_EVENT_RECEIVE;
98
99 if( !FCB->ReceiveIrp.InFlightRequest ) {
100 AFD_DbgPrint(MID_TRACE,("Replenishing buffer\n"));
101
102 SocketCalloutEnter( FCB );
103
104 Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
105 FCB->Connection.Object,
106 TDI_RECEIVE_NORMAL,
107 FCB->Recv.Window,
108 FCB->Recv.Size,
109 &FCB->ReceiveIrp.Iosb,
110 ReceiveComplete,
111 FCB );
112
113 SocketCalloutLeave( FCB );
114
115 if( Status == STATUS_SUCCESS )
116 FCB->Recv.Content = FCB->ReceiveIrp.Iosb.Information;
117 HandleEOFOnIrp( FCB, Status, FCB->ReceiveIrp.Iosb.Information );
118 }
119 }
120
121 return STATUS_SUCCESS;
122 }
123
124 static NTSTATUS ReceiveActivity( PAFD_FCB FCB, PIRP Irp ) {
125 PLIST_ENTRY NextIrpEntry;
126 PIRP NextIrp;
127 PIO_STACK_LOCATION NextIrpSp;
128 PAFD_RECV_INFO RecvReq;
129 UINT TotalBytesCopied = 0;
130 NTSTATUS Status = STATUS_SUCCESS, RetStatus = STATUS_PENDING;
131
132 AFD_DbgPrint(MID_TRACE,("%x %x\n", FCB, Irp));
133
134 if( CantReadMore( FCB ) ) {
135 /* Success here means that we got an EOF. Complete a pending read
136 * with zero bytes if we haven't yet overread, then kill the others.
137 */
138 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
139 NextIrpEntry =
140 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
141 NextIrp =
142 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
143 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
144 RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
145
146 AFD_DbgPrint(MID_TRACE,("Completing recv %x (%d)\n", NextIrp,
147 TotalBytesCopied));
148 UnlockBuffers( RecvReq->BufferArray,
149 RecvReq->BufferCount, FALSE );
150 Status = NextIrp->IoStatus.Status =
151 FCB->Overread ? STATUS_END_OF_FILE : STATUS_SUCCESS;
152 NextIrp->IoStatus.Information = 0;
153 if( NextIrp == Irp ) RetStatus = Status;
154 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
155 FCB->Overread = TRUE;
156 //FCB->PollState |= AFD_EVENT_DISCONNECT;
157 PollReeval( FCB->DeviceExt, FCB->FileObject );
158 }
159 } else {
160 /* Kick the user that receive would be possible now */
161 /* XXX Not implemented yet */
162
163 AFD_DbgPrint(MID_TRACE,("FCB %x Receive data waiting %d\n",
164 FCB, FCB->Recv.Content));
165 /*OskitDumpBuffer( FCB->Recv.Window, FCB->Recv.Content );*/
166
167 Status = STATUS_SUCCESS;
168
169 /* Try to clear some requests */
170 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) &&
171 NT_SUCCESS(Status) ) {
172 NextIrpEntry =
173 RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
174 NextIrp =
175 CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
176 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
177 RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
178
179 AFD_DbgPrint(MID_TRACE,("RecvReq @ %x\n", RecvReq));
180
181 Status = TryToSatisfyRecvRequestFromBuffer
182 ( FCB, RecvReq, &TotalBytesCopied );
183
184 if( Status == STATUS_PENDING ) {
185 AFD_DbgPrint(MID_TRACE,("Ran out of data for %x\n", NextIrp));
186 InsertHeadList(&FCB->PendingIrpList[FUNCTION_RECV],
187 &NextIrp->Tail.Overlay.ListEntry);
188 break;
189 } else {
190 AFD_DbgPrint(MID_TRACE,("Completing recv %x (%d)\n", NextIrp,
191 TotalBytesCopied));
192 UnlockBuffers( RecvReq->BufferArray,
193 RecvReq->BufferCount, FALSE );
194 NextIrp->IoStatus.Status = Status;
195 NextIrp->IoStatus.Information = TotalBytesCopied;
196 if( NextIrp == Irp ) RetStatus = Status;
197 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
198 }
199 }
200 }
201
202 if( FCB->Recv.Content ) {
203 FCB->PollState |= AFD_EVENT_RECEIVE;
204 } else
205 FCB->PollState &= ~AFD_EVENT_RECEIVE;
206
207 PollReeval( FCB->DeviceExt, FCB->FileObject );
208
209 AFD_DbgPrint(MID_TRACE,("RetStatus for irp %x is %x\n", Irp, RetStatus));
210
211 return RetStatus;
212 }
213
214 NTSTATUS NTAPI ReceiveComplete
215 ( PDEVICE_OBJECT DeviceObject,
216 PIRP Irp,
217 PVOID Context ) {
218 NTSTATUS Status = Irp->IoStatus.Status;
219 PAFD_FCB FCB = (PAFD_FCB)Context;
220
221 AFD_DbgPrint(MID_TRACE,("Called\n"));
222
223 ASSERT_IRQL(APC_LEVEL);
224
225 if( !SocketAcquireStateLock( FCB ) ) return Status;
226
227 FCB->ReceiveIrp.InFlightRequest = NULL;
228 FCB->Recv.Content = Irp->IoStatus.Information;
229 FCB->Recv.BytesUsed = 0;
230
231 if( FCB->State == SOCKET_STATE_CLOSED ) {
232 AFD_DbgPrint(MIN_TRACE,("!!! CLOSED SOCK GOT A RECEIVE COMPLETE !!!\n"));
233 SocketStateUnlock( FCB );
234 DestroySocket( FCB );
235 return STATUS_SUCCESS;
236 } else if( FCB->State == SOCKET_STATE_LISTENING ) {
237 AFD_DbgPrint(MIN_TRACE,("!!! LISTENER GOT A RECEIVE COMPLETE !!!\n"));
238 SocketStateUnlock( FCB );
239 return STATUS_UNSUCCESSFUL;
240 }
241
242 HandleEOFOnIrp( FCB, Irp->IoStatus.Status, Irp->IoStatus.Information );
243
244 ReceiveActivity( FCB, NULL );
245
246 PollReeval( FCB->DeviceExt, FCB->FileObject );
247
248 SocketStateUnlock( FCB );
249
250 AFD_DbgPrint(MID_TRACE,("Returned %x\n", Status));
251
252 return STATUS_SUCCESS;
253 }
254
255 NTSTATUS STDCALL
256 AfdConnectedSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
257 PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
258 NTSTATUS Status = STATUS_INVALID_PARAMETER;
259 PFILE_OBJECT FileObject = IrpSp->FileObject;
260 PAFD_FCB FCB = FileObject->FsContext;
261 PAFD_RECV_INFO RecvReq;
262 UINT TotalBytesCopied = 0;
263
264 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
265
266 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
267
268 if( FCB->State != SOCKET_STATE_CONNECTED &&
269 FCB->State != SOCKET_STATE_CONNECTING ) {
270 AFD_DbgPrint(MID_TRACE,("Called recv on wrong kind of socket (s%x)\n",
271 FCB->State));
272 return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL,
273 Irp, 0, NULL, FALSE );
274 }
275
276 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
277 {
278 AFD_DbgPrint(MID_TRACE,("Receive on connection-less sockets not implemented\n"));
279 return UnlockAndMaybeComplete( FCB, STATUS_NOT_IMPLEMENTED,
280 Irp, 0, NULL, FALSE );
281 }
282
283 FCB->EventsFired &= ~AFD_EVENT_RECEIVE;
284 PollReeval( FCB->DeviceExt, FCB->FileObject );
285
286 if( !(RecvReq = LockRequest( Irp, IrpSp )) )
287 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY,
288 Irp, 0, NULL, FALSE );
289
290 AFD_DbgPrint(MID_TRACE,("Recv flags %x\n", RecvReq->AfdFlags));
291
292 RecvReq->BufferArray = LockBuffers( RecvReq->BufferArray,
293 RecvReq->BufferCount,
294 NULL, NULL,
295 TRUE, FALSE );
296
297 if( !RecvReq->BufferArray ) {
298 return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
299 Irp, 0, NULL, FALSE );
300 }
301
302 Irp->IoStatus.Status = STATUS_PENDING;
303 Irp->IoStatus.Information = 0;
304
305 InsertTailList( &FCB->PendingIrpList[FUNCTION_RECV],
306 &Irp->Tail.Overlay.ListEntry );
307
308 /************ From this point, the IRP is not ours ************/
309
310 Status = ReceiveActivity( FCB, Irp );
311
312 if( Status == STATUS_PENDING && RecvReq->AfdFlags & AFD_IMMEDIATE ) {
313 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
314 Status = STATUS_CANT_WAIT;
315 TotalBytesCopied = 0;
316 RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
317 UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, FALSE );
318 return UnlockAndMaybeComplete( FCB, Status, Irp,
319 TotalBytesCopied, NULL, TRUE );
320 } else if( Status == STATUS_PENDING ) {
321 AFD_DbgPrint(MID_TRACE,("Leaving read irp\n"));
322 IoMarkIrpPending( Irp );
323 } else {
324 AFD_DbgPrint(MID_TRACE,("Completed with status %x\n", Status));
325 }
326
327 SocketStateUnlock( FCB );
328 return Status;
329 }
330
331
332 static NTSTATUS STDCALL
333 SatisfyPacketRecvRequest( PAFD_FCB FCB, PIRP Irp,
334 PAFD_STORED_DATAGRAM DatagramRecv,
335 PUINT TotalBytesCopied ) {
336 NTSTATUS Status = STATUS_SUCCESS;
337 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
338 PAFD_RECV_INFO RecvReq =
339 IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
340 UINT BytesToCopy = 0, BytesAvailable = DatagramRecv->Len, AddrLen = 0;
341 PAFD_MAPBUF Map;
342
343 Map = (PAFD_MAPBUF)(RecvReq->BufferArray +
344 RecvReq->BufferCount +
345 EXTRA_LOCK_BUFFERS);
346
347 BytesToCopy =
348 MIN( RecvReq->BufferArray[0].len, BytesAvailable );
349
350 AFD_DbgPrint(MID_TRACE,("BytesToCopy: %d len %d\n", BytesToCopy,
351 RecvReq->BufferArray[0].len));
352
353 if( Map[0].Mdl ) {
354 /* Copy the address */
355 if( Map[1].Mdl && Map[2].Mdl ) {
356 AFD_DbgPrint(MID_TRACE,("Checking TAAddressCount\n"));
357
358 if( DatagramRecv->Address->TAAddressCount != 1 ) {
359 AFD_DbgPrint
360 (MID_TRACE,
361 ("Wierd address count %d\n",
362 DatagramRecv->Address->TAAddressCount));
363 }
364
365 AFD_DbgPrint(MID_TRACE,("Computing addr len\n"));
366
367 AddrLen = MIN(DatagramRecv->Address->Address->AddressLength +
368 sizeof(USHORT),
369 RecvReq->BufferArray[1].len);
370
371 AFD_DbgPrint(MID_TRACE,("Copying %d bytes of address\n", AddrLen));
372
373 Map[1].BufferAddress = MmMapLockedPages( Map[1].Mdl, KernelMode );
374
375 AFD_DbgPrint(MID_TRACE,("Done mapping, copying address\n"));
376
377 RtlCopyMemory( Map[1].BufferAddress,
378 &DatagramRecv->Address->Address->AddressType,
379 AddrLen );
380
381 MmUnmapLockedPages( Map[1].BufferAddress, Map[1].Mdl );
382
383 AFD_DbgPrint(MID_TRACE,("Copying address len\n"));
384
385 Map[2].BufferAddress = MmMapLockedPages( Map[2].Mdl, KernelMode );
386 *((PINT)Map[2].BufferAddress) = AddrLen;
387 MmUnmapLockedPages( Map[2].BufferAddress, Map[2].Mdl );
388 }
389
390 AFD_DbgPrint(MID_TRACE,("Mapping data buffer pages\n"));
391
392 Map[0].BufferAddress = MmMapLockedPages( Map[0].Mdl, KernelMode );
393
394 AFD_DbgPrint(MID_TRACE,("Buffer %d: %x:%d\n",
395 0,
396 Map[0].BufferAddress,
397 BytesToCopy));
398
399 /* OskitDumpBuffer
400 ( FCB->Recv.Window + FCB->Recv.BytesUsed, BytesToCopy ); */
401
402 RtlCopyMemory( Map[0].BufferAddress,
403 FCB->Recv.Window + FCB->Recv.BytesUsed,
404 BytesToCopy );
405
406 MmUnmapLockedPages( Map[0].BufferAddress, Map[0].Mdl );
407
408 FCB->Recv.BytesUsed = 0;
409 *TotalBytesCopied = BytesToCopy;
410 }
411
412 Status = Irp->IoStatus.Status = STATUS_SUCCESS;
413 Irp->IoStatus.Information = BytesToCopy;
414 ExFreePool( DatagramRecv->Address );
415 ExFreePool( DatagramRecv );
416
417 AFD_DbgPrint(MID_TRACE,("Done\n"));
418
419 return Status;
420 }
421
422 NTSTATUS NTAPI
423 PacketSocketRecvComplete(
424 PDEVICE_OBJECT DeviceObject,
425 PIRP Irp,
426 PVOID Context ) {
427 NTSTATUS Status = STATUS_SUCCESS;
428 PAFD_FCB FCB = Context;
429 PIRP NextIrp;
430 PIO_STACK_LOCATION NextIrpSp;
431 PLIST_ENTRY ListEntry;
432 PAFD_RECV_INFO RecvReq;
433 PAFD_STORED_DATAGRAM DatagramRecv;
434 UINT DGSize = Irp->IoStatus.Information + sizeof( AFD_STORED_DATAGRAM );
435
436 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
437
438 if( !SocketAcquireStateLock( FCB ) ) return STATUS_UNSUCCESSFUL;
439
440 FCB->ReceiveIrp.InFlightRequest = NULL;
441
442 if( FCB->State == SOCKET_STATE_CLOSED ) {
443 SocketStateUnlock( FCB );
444 DestroySocket( FCB );
445 return STATUS_SUCCESS;
446 }
447
448 DatagramRecv = ExAllocatePool( NonPagedPool, DGSize );
449
450 if( DatagramRecv ) {
451 DatagramRecv->Len = Irp->IoStatus.Information;
452 RtlCopyMemory( DatagramRecv->Buffer, FCB->Recv.Window,
453 DatagramRecv->Len );
454 AFD_DbgPrint(MID_TRACE,("Received (A %x)\n",
455 FCB->AddressFrom->RemoteAddress));
456 DatagramRecv->Address =
457 TaCopyTransportAddress( FCB->AddressFrom->RemoteAddress );
458
459 InsertTailList( &FCB->DatagramList, &DatagramRecv->ListEntry );
460 } else Status = STATUS_NO_MEMORY;
461
462 /* Satisfy as many requests as we can */
463
464 while( NT_SUCCESS(Status) &&
465 !IsListEmpty( &FCB->DatagramList ) &&
466 !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
467 AFD_DbgPrint(MID_TRACE,("Looping trying to satisfy request\n"));
468 ListEntry = RemoveHeadList( &FCB->DatagramList );
469 DatagramRecv = CONTAINING_RECORD( ListEntry, AFD_STORED_DATAGRAM,
470 ListEntry );
471 ListEntry = RemoveHeadList( &FCB->PendingIrpList[FUNCTION_RECV] );
472 NextIrp = CONTAINING_RECORD( ListEntry, IRP, Tail.Overlay.ListEntry );
473 NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
474 RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
475
476 AFD_DbgPrint(MID_TRACE,("RecvReq: %x, DatagramRecv: %x\n",
477 RecvReq, DatagramRecv));
478
479 if( DatagramRecv->Len > RecvReq->BufferArray[0].len &&
480 !(RecvReq->TdiFlags & TDI_RECEIVE_PARTIAL) ) {
481 InsertHeadList( &FCB->DatagramList,
482 &DatagramRecv->ListEntry );
483 Status = NextIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
484 NextIrp->IoStatus.Information = DatagramRecv->Len;
485 UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
486 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
487 } else {
488 AFD_DbgPrint(MID_TRACE,("Satisfying\n"));
489 Status = SatisfyPacketRecvRequest
490 ( FCB, NextIrp, DatagramRecv,
491 (PUINT)&NextIrp->IoStatus.Information );
492 AFD_DbgPrint(MID_TRACE,("Unlocking\n"));
493 UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
494 AFD_DbgPrint(MID_TRACE,("Completing\n"));
495 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
496 }
497 }
498
499 if( !IsListEmpty( &FCB->DatagramList ) ) {
500 AFD_DbgPrint(MID_TRACE,("Signalling\n"));
501 FCB->PollState |= AFD_EVENT_RECEIVE;
502 } else
503 FCB->PollState &= ~AFD_EVENT_RECEIVE;
504
505 PollReeval( FCB->DeviceExt, FCB->FileObject );
506
507 if( NT_SUCCESS(Irp->IoStatus.Status) ) {
508 /* Now relaunch the datagram request */
509 SocketCalloutEnter( FCB );
510
511 Status = TdiReceiveDatagram
512 ( &FCB->ReceiveIrp.InFlightRequest,
513 FCB->AddressFile.Object,
514 0,
515 FCB->Recv.Window,
516 FCB->Recv.Size,
517 FCB->AddressFrom,
518 &FCB->ReceiveIrp.Iosb,
519 PacketSocketRecvComplete,
520 FCB );
521
522 SocketCalloutLeave( FCB );
523 }
524
525 SocketStateUnlock( FCB );
526
527 return STATUS_SUCCESS;
528 }
529
530 NTSTATUS STDCALL
531 AfdPacketSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
532 PIO_STACK_LOCATION IrpSp ) {
533 NTSTATUS Status = STATUS_SUCCESS;
534 PFILE_OBJECT FileObject = IrpSp->FileObject;
535 PAFD_FCB FCB = FileObject->FsContext;
536 PAFD_RECV_INFO_UDP RecvReq;
537 PLIST_ENTRY ListEntry;
538 PAFD_STORED_DATAGRAM DatagramRecv;
539
540 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
541
542 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
543
544 FCB->EventsFired &= ~AFD_EVENT_RECEIVE;
545
546 /* Check that the socket is bound */
547 if( FCB->State != SOCKET_STATE_BOUND )
548 return UnlockAndMaybeComplete
549 ( FCB, STATUS_UNSUCCESSFUL, Irp, 0, NULL, FALSE );
550 if( !(RecvReq = LockRequest( Irp, IrpSp )) )
551 return UnlockAndMaybeComplete
552 ( FCB, STATUS_NO_MEMORY, Irp, 0, NULL, FALSE );
553
554 AFD_DbgPrint(MID_TRACE,("Recv flags %x\n", RecvReq->AfdFlags));
555
556 RecvReq->BufferArray = LockBuffers( RecvReq->BufferArray,
557 RecvReq->BufferCount,
558 RecvReq->Address,
559 RecvReq->AddressLength,
560 TRUE, TRUE );
561
562 if( !RecvReq->BufferArray ) { /* access violation in userspace */
563 return UnlockAndMaybeComplete
564 ( FCB, STATUS_ACCESS_VIOLATION, Irp, 0, NULL, FALSE );
565 }
566
567 if( !IsListEmpty( &FCB->DatagramList ) ) {
568 ListEntry = RemoveHeadList( &FCB->DatagramList );
569 DatagramRecv = CONTAINING_RECORD
570 ( ListEntry, AFD_STORED_DATAGRAM, ListEntry );
571 if( DatagramRecv->Len > RecvReq->BufferArray[0].len &&
572 !(RecvReq->TdiFlags & TDI_RECEIVE_PARTIAL) ) {
573 InsertHeadList( &FCB->DatagramList,
574 &DatagramRecv->ListEntry );
575 Status = Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
576 Irp->IoStatus.Information = DatagramRecv->Len;
577
578 if( IsListEmpty( &FCB->DatagramList ) )
579 FCB->PollState &= ~AFD_EVENT_RECEIVE;
580 else
581 FCB->PollState |= AFD_EVENT_RECEIVE;
582
583 PollReeval( FCB->DeviceExt, FCB->FileObject );
584
585 return UnlockAndMaybeComplete
586 ( FCB, Status, Irp, RecvReq->BufferArray[0].len, NULL, TRUE );
587 } else {
588 Status = SatisfyPacketRecvRequest
589 ( FCB, Irp, DatagramRecv,
590 (PUINT)&Irp->IoStatus.Information );
591
592 if( IsListEmpty( &FCB->DatagramList ) )
593 FCB->PollState &= ~AFD_EVENT_RECEIVE;
594 else
595 FCB->PollState |= AFD_EVENT_RECEIVE;
596
597 PollReeval( FCB->DeviceExt, FCB->FileObject );
598
599 return UnlockAndMaybeComplete
600 ( FCB, Status, Irp, Irp->IoStatus.Information, NULL, TRUE );
601 }
602 } else if( RecvReq->AfdFlags & AFD_IMMEDIATE ) {
603 AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
604 Status = STATUS_CANT_WAIT;
605 PollReeval( FCB->DeviceExt, FCB->FileObject );
606 return UnlockAndMaybeComplete( FCB, Status, Irp, 0, NULL, TRUE );
607 } else {
608 PollReeval( FCB->DeviceExt, FCB->FileObject );
609 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_RECV );
610 }
611 }