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