:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / net / tcpip / transport / datagram / datagram.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        transport/datagram/datagram.c
5  * PURPOSE:     Routines for sending and receiving datagrams
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 #include <tcpip.h>
11 #include <datagram.h>
12 #include <routines.h>
13 #include <transmit.h>
14 #include <address.h>
15 #include <route.h>
16 #include <pool.h>
17
18
19 /* Pending request queue */
20 LIST_ENTRY DGPendingListHead;
21 KSPIN_LOCK DGPendingListLock;
22 /* Work queue item for pending requests */
23 WORK_QUEUE_ITEM DGWorkItem;
24
25
26 VOID DatagramWorker(
27   PVOID Context)
28 /*
29  * FUNCTION: Handles pending send requests
30  * ARGUMENTS:
31  *     Context = Pointer to context information (unused)
32  * NOTES:
33  *     This routine is called after the driver has run out of resources.
34  *     It processes send requests or shedules them to be processed
35  */
36 {
37   PLIST_ENTRY CurrentADFEntry;
38   PLIST_ENTRY CurrentSREntry;
39   PADDRESS_FILE CurrentADF;
40   PDATAGRAM_SEND_REQUEST CurrentSR;
41   KIRQL OldIrql1;
42   KIRQL OldIrql2;
43
44   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
45
46   KeAcquireSpinLock(&DGPendingListLock, &OldIrql1);
47
48   CurrentADFEntry = DGPendingListHead.Flink;
49   while (CurrentADFEntry != &DGPendingListHead) {
50     RemoveEntryList(CurrentADFEntry);
51     CurrentADF = CONTAINING_RECORD(CurrentADFEntry,
52                                    ADDRESS_FILE,
53                                    ListEntry);
54
55     KeAcquireSpinLock(&CurrentADF->Lock, &OldIrql2);
56
57     if (AF_IS_BUSY(CurrentADF)) {
58       /* The send worker function is already running so we just
59          set the pending send flag on the address file object */
60
61       AF_SET_PENDING(CurrentADF, AFF_SEND);
62       KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);
63     } else {
64       if (!IsListEmpty(&CurrentADF->TransmitQueue)) {
65         /* The transmit queue is not empty. Dequeue a send
66            request and process it */
67
68         CurrentSREntry = RemoveHeadList(&CurrentADF->TransmitQueue);
69         CurrentSR      = CONTAINING_RECORD(CurrentADFEntry,
70                                            DATAGRAM_SEND_REQUEST,
71                                            ListEntry);
72
73         KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);
74
75         DGSend(CurrentADF, CurrentSR);
76       } else
77         KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);
78     }
79     CurrentADFEntry = CurrentADFEntry->Flink;
80   }
81
82   KeReleaseSpinLock(&DGPendingListLock, OldIrql1);
83
84   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
85 }
86
87
88 VOID SendDatagramComplete(
89   PVOID Context,
90   PNDIS_PACKET Packet,
91   NDIS_STATUS NdisStatus)
92 /*
93  * FUNCTION: Datagram transmit completion handler
94  * ARGUMENTS:
95  *     Context    = Pointer to context infomation (DATAGRAM_SEND_REQUEST)
96  *     Packet     = Pointer to NDIS packet
97  *     NdisStatus = Status of transmit operation
98  * NOTES:
99  *     This routine is called by IP when a datagram send completes.
100  *     We shedule the out-of-resource worker function if there
101  *     are pending address files in the queue
102  */
103 {
104   KIRQL OldIrql;
105   ULONG BytesSent;
106   PVOID CompleteContext;
107   PNDIS_BUFFER NdisBuffer;
108   PDATAGRAM_SEND_REQUEST SendRequest;
109   DATAGRAM_COMPLETION_ROUTINE Complete;
110   BOOLEAN QueueWorkItem;
111
112   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
113
114   SendRequest     = (PDATAGRAM_SEND_REQUEST)Context;
115   Complete        = SendRequest->Complete;
116   CompleteContext = SendRequest->Context;
117   BytesSent       = SendRequest->BufferSize;
118
119   /* Remove data buffer before releasing memory for packet buffers */
120   NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
121   NdisUnchainBufferAtBack(Packet, &NdisBuffer);
122   FreeNdisPacket(Packet);
123   DereferenceObject(SendRequest->RemoteAddress);
124   ExFreePool(SendRequest);
125
126   /* If there are pending send requests, shedule worker function */
127   KeAcquireSpinLock(&DGPendingListLock, &OldIrql);
128   QueueWorkItem = (!IsListEmpty(&DGPendingListHead));
129   KeReleaseSpinLock(&DGPendingListLock, OldIrql);
130   if (QueueWorkItem)
131     ExQueueWorkItem(&DGWorkItem, CriticalWorkQueue);
132
133   TI_DbgPrint(MAX_TRACE, ("Calling 0x%X.\n", Complete));
134
135   /* Call completion routine for send request */
136   (*Complete)(CompleteContext, NdisStatus, BytesSent);
137
138   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
139 }
140
141
142 VOID DGSend(
143   PVOID Context,
144   PDATAGRAM_SEND_REQUEST SendRequest)
145 /*
146  * FUNCTION: Sends a datagram to IP layer
147  * ARGUMENTS:
148  *     Context     = Pointer to context information (ADDRESS_FILE)
149  *     SendRequest = Pointer to send request
150  */
151 {
152   KIRQL OldIrql;
153   NTSTATUS Status;
154   USHORT LocalPort;
155   PIP_PACKET IPPacket;
156   PROUTE_CACHE_NODE RCN;
157   PLIST_ENTRY CurrentEntry;
158   PADDRESS_FILE AddrFile = Context;
159   PADDRESS_ENTRY ADE;
160
161   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
162
163   /* Get the information we need from the address file
164      now so we minimize the time we hold the spin lock */
165   KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
166   LocalPort = AddrFile->Port;
167   ADE       = AddrFile->ADE;
168   ReferenceObject(ADE);
169   KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
170
171   /* Loop until there are no more send requests in the
172      transmit queue or until we run out of resources */
173   for (;;) {
174     Status = (*SendRequest->Build)(SendRequest, ADE->Address, LocalPort, &IPPacket);
175     if (!NT_SUCCESS(Status)) {
176       KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
177       /* An error occurred, enqueue the send request again and return */
178       InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry);
179       DereferenceObject(ADE);
180       KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
181
182       TI_DbgPrint(MIN_TRACE, ("Leaving (insufficient resources).\n"));
183       return;
184     }
185
186     /* Get a route to the destination address */
187     if (RouteGetRouteToDestination(SendRequest->RemoteAddress, ADE->NTE, &RCN) == IP_SUCCESS) {
188       /* Set completion routine and send the packet */
189       PC(IPPacket->NdisPacket)->Complete = SendDatagramComplete;
190       PC(IPPacket->NdisPacket)->Context  = SendRequest;
191       if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS)
192           SendDatagramComplete(
193             SendRequest,
194             IPPacket->NdisPacket,
195             NDIS_STATUS_REQUEST_ABORTED);
196       /* We're done with the RCN */
197       DereferenceObject(RCN);
198     } else {
199       /* No route to destination */
200       /* FIXME: Which error code should we use here? */
201       TI_DbgPrint(MIN_TRACE, ("No route to destination address (0x%X).\n",
202           SendRequest->RemoteAddress->Address.IPv4Address));
203       SendDatagramComplete(
204         SendRequest,
205         IPPacket->NdisPacket,
206         NDIS_STATUS_REQUEST_ABORTED);
207     }
208
209     (*IPPacket->Free)(IPPacket);
210
211     /* Check transmit queue for more to send */
212
213     KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
214
215     if (!IsListEmpty(&AddrFile->TransmitQueue)) {
216       /* Transmit queue is not empty, process one more request */
217       CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);
218       SendRequest  = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
219
220       KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
221     } else {
222       /* Transmit queue is empty */
223       AF_CLR_PENDING(AddrFile, AFF_SEND);
224       DereferenceObject(ADE);
225       KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
226
227       TI_DbgPrint(MAX_TRACE, ("Leaving (empty queue).\n"));
228       return;
229     }
230   }
231 }
232
233
234 VOID DGDeliverData(
235   PADDRESS_FILE AddrFile,
236   PIP_ADDRESS Address,
237   PIP_PACKET IPPacket,
238   UINT DataSize)
239 /*
240  * FUNCTION: Delivers datagram data to a user
241  * ARGUMENTS:
242  *     AddrFile = Address file to deliver data to
243  *     Address  = Remote address the packet came from
244  *     IPPacket = Pointer to IP packet to deliver
245  *     DataSize = Number of bytes in data area
246  *                (incl. IP header for raw IP file objects)
247  * NOTES:
248  *     If there is a receive request, then we copy the data to the
249  *     buffer supplied by the user and complete the receive request.
250  *     If no suitable receive request exists, then we call the event
251  *     handler if it exists, otherwise we drop the packet.
252  */
253 {
254   KIRQL OldIrql;
255   PTDI_IND_RECEIVE_DATAGRAM ReceiveHandler;
256   PVOID HandlerContext;
257   LONG AddressLength;
258   PVOID SourceAddress;
259   ULONG BytesTaken;
260   NTSTATUS Status;
261   PVOID DataBuffer;
262
263   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
264
265   KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
266
267   if (AddrFile->Protocol == IPPROTO_UDP) {
268     DataBuffer = IPPacket->Data;
269   } else {
270     /* Give client the IP header too if it is a raw IP file object */
271     DataBuffer = IPPacket->Header;
272   }
273
274   if (!IsListEmpty(&AddrFile->ReceiveQueue)) {
275     PLIST_ENTRY CurrentEntry;
276     PDATAGRAM_RECEIVE_REQUEST Current;
277     BOOLEAN Found;
278
279     TI_DbgPrint(MAX_TRACE, ("There is a receive request.\n"));
280
281     /* Search receive request list to find a match */
282     Found = FALSE;
283     CurrentEntry = AddrFile->ReceiveQueue.Flink;
284     while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) {
285       Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
286       if (!Current->RemoteAddress)
287         Found = TRUE;
288       else if (AddrIsEqual(Address, Current->RemoteAddress))
289         Found = TRUE;
290
291       if (Found) {
292         /* FIXME: Maybe we should check if the buffer of this
293            receive request is large enough and if not, search
294            for another */
295
296         /* Remove the request from the queue */
297         RemoveEntryList(&Current->ListEntry);
298         AddrFile->RefCount--;
299         break;
300       }
301       CurrentEntry = CurrentEntry->Flink;
302     }
303
304     KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
305
306     if (Found) {
307       TI_DbgPrint(MAX_TRACE, ("Suitable receive request found.\n"));
308
309       /* Copy the data into buffer provided by the user */
310       CopyBufferToBufferChain(
311         Current->Buffer,
312         0,
313         DataBuffer,
314         DataSize);
315
316       /* Complete the receive request */
317       (*Current->Complete)(Current->Context, STATUS_SUCCESS, DataSize);
318
319       /* Finally free the receive request */
320       if (Current->RemoteAddress)
321         DereferenceObject(Current->RemoteAddress);
322       ExFreePool(Current);
323     }
324   } else if (AddrFile->RegisteredReceiveDatagramHandler) {
325     TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n"));
326
327     ReceiveHandler = AddrFile->ReceiveDatagramHandler;
328     HandlerContext = AddrFile->ReceiveDatagramHandlerContext;
329
330     KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
331
332     if (Address->Type == IP_ADDRESS_V4) {
333       AddressLength = sizeof(IPv4_RAW_ADDRESS);
334       SourceAddress = &Address->Address.IPv4Address;
335     } else /* (Address->Type == IP_ADDRESS_V6) */ {
336       AddressLength = sizeof(IPv6_RAW_ADDRESS);
337       SourceAddress = Address->Address.IPv6Address;
338     }
339
340     Status = (*ReceiveHandler)(
341       HandlerContext,
342       AddressLength,
343       SourceAddress,
344       0,
345       NULL,
346       TDI_RECEIVE_ENTIRE_MESSAGE,
347       DataSize,
348       DataSize,
349       &BytesTaken,
350       DataBuffer,
351       NULL);
352   } else {
353     TI_DbgPrint(MAX_TRACE, ("Discarding datagram.\n"));
354   }
355
356   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
357 }
358
359
360 VOID DGCancelSendRequest(
361   PADDRESS_FILE AddrFile,
362   PVOID Context)
363 /*
364  * FUNCTION: Cancels a datagram send request
365  * ARGUMENTS:
366  *     AddrFile = Pointer to address file of the request
367  *     Context  = Pointer to context information for completion handler
368  */
369 {
370   KIRQL OldIrql;
371   PLIST_ENTRY CurrentEntry;
372   PDATAGRAM_SEND_REQUEST Current = NULL;
373   BOOLEAN Found = FALSE;
374
375   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
376
377   KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
378
379   /* Search the request list for the specified request and remove it */
380   CurrentEntry = AddrFile->TransmitQueue.Flink;
381   while ((CurrentEntry != &AddrFile->TransmitQueue) && (!Found)) {
382           Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
383     if (Context == Current->Context) {
384       /* We've found the request, now remove it from the queue */
385       RemoveEntryList(CurrentEntry);
386       AddrFile->RefCount--;
387       Found = TRUE;
388       break;
389     }
390     CurrentEntry = CurrentEntry->Flink;
391   }
392
393   KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
394
395   if (Found) {
396     /* Complete the request and free its resources */
397     (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0);
398     DereferenceObject(Current->RemoteAddress);
399     ExFreePool(Current);
400   } else {
401     TI_DbgPrint(MID_TRACE, ("Cannot find send request.\n"));
402   }
403 }
404
405
406 VOID DGCancelReceiveRequest(
407   PADDRESS_FILE AddrFile,
408   PVOID Context)
409 /*
410  * FUNCTION: Cancels a datagram receive request
411  * ARGUMENTS:
412  *     AddrFile = Pointer to address file of the request
413  *     Context  = Pointer to context information for completion handler
414  */
415 {
416   KIRQL OldIrql;
417   PLIST_ENTRY CurrentEntry;
418   PDATAGRAM_RECEIVE_REQUEST Current = NULL;
419   BOOLEAN Found = FALSE;
420
421   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
422
423   KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
424
425   /* Search the request list for the specified request and remove it */
426   CurrentEntry = AddrFile->ReceiveQueue.Flink;
427   while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) {
428           Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
429     if (Context == Current->Context) {
430       /* We've found the request, now remove it from the queue */
431       RemoveEntryList(CurrentEntry);
432       AddrFile->RefCount--;
433       Found = TRUE;
434       break;
435     }
436     CurrentEntry = CurrentEntry->Flink;
437   }
438
439   KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
440
441   if (Found) {
442     /* Complete the request and free its resources */
443     (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0);
444     /* Remote address can be NULL if the caller wants to receive
445        packets sent from any address */
446     if (Current->RemoteAddress)
447       DereferenceObject(Current->RemoteAddress);
448     ExFreePool(Current);
449   } else {
450     TI_DbgPrint(MID_TRACE, ("Cannot find receive request.\n"));
451   }
452 }
453
454
455 NTSTATUS DGTransmit(
456   PADDRESS_FILE AddressFile,
457   PDATAGRAM_SEND_REQUEST SendRequest)
458 /*
459  * FUNCTION: Transmits or queues a send request
460  * ARGUMENTS:
461  *     AddressFile = Pointer to address file
462  *     SendRequest = Pointer to send request
463  * RETURNS:
464  *     Status of operation
465  */
466 {
467   KIRQL OldIrql;
468 CP
469   KeAcquireSpinLock(&AddressFile->Lock, &OldIrql);
470 CP
471   if (AF_IS_BUSY(AddressFile)) {
472 CP
473     /* Queue send request on the transmit queue */
474     InsertTailList(&AddressFile->TransmitQueue, &SendRequest->ListEntry);
475 CP
476     /* Reference address file and set pending send request flag */
477     ReferenceObject(AddressFile);
478 CP
479     AF_SET_PENDING(AddressFile, AFF_SEND);
480 CP
481     KeReleaseSpinLock(&AddressFile->Lock, OldIrql);
482 CP
483     TI_DbgPrint(MAX_TRACE, ("Leaving (queued).\n"));
484   } else {
485 CP
486     KeReleaseSpinLock(&AddressFile->Lock, OldIrql);
487 CP
488     /* Send the datagram */
489     DGSend(AddressFile, SendRequest);
490 CP
491     TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
492   }
493 CP
494   return STATUS_PENDING;
495 }
496
497 NTSTATUS DGSendDatagram(
498   PTDI_REQUEST Request,
499   PTDI_CONNECTION_INFORMATION ConnInfo,
500   PNDIS_BUFFER Buffer,
501   ULONG DataSize,
502   DATAGRAM_BUILD_ROUTINE Build)
503 /*
504  * FUNCTION: Sends a datagram to a remote address
505  * ARGUMENTS:
506  *     Request   = Pointer to TDI request
507  *     ConnInfo  = Pointer to connection information
508  *     Buffer    = Pointer to NDIS buffer with data
509  *     DataSize  = Size in bytes of data to be sent
510  *     Build     = Pointer to datagram build routine
511  * RETURNS:
512  *     Status of operation
513  */
514 {
515   PADDRESS_FILE AddrFile;
516   KIRQL OldIrql;
517   NTSTATUS Status;
518   PDATAGRAM_SEND_REQUEST SendRequest;
519
520   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
521
522   AddrFile = Request->Handle.AddressHandle;
523
524   KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
525
526   if (AF_IS_VALID(AddrFile)) {
527     /* Initialize a send request */
528     Status = BuildDatagramSendRequest(
529       &SendRequest,
530       NULL,
531       0,
532       Buffer,
533       DataSize,
534       Request->RequestNotifyObject,
535       Request->RequestContext,
536       Build,
537       0);
538     if (NT_SUCCESS(Status)) {
539       Status = AddrGetAddress(
540         ConnInfo->RemoteAddress,
541         &SendRequest->RemoteAddress,
542         &SendRequest->RemotePort,
543         &AddrFile->AddrCache);
544       if (NT_SUCCESS(Status)) {
545         KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
546         return DGTransmit(AddrFile, SendRequest);
547       } else {
548         ExFreePool(SendRequest);
549       }
550     } else
551       Status = STATUS_INSUFFICIENT_RESOURCES;
552   } else
553     Status = STATUS_ADDRESS_CLOSED;
554
555   KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
556
557   TI_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X)\n", Status));
558
559   return Status;
560 }
561
562
563 NTSTATUS DGReceiveDatagram(
564   PTDI_REQUEST Request,
565   PTDI_CONNECTION_INFORMATION ConnInfo,
566   PNDIS_BUFFER Buffer,
567   ULONG ReceiveLength,
568   ULONG ReceiveFlags,
569   PTDI_CONNECTION_INFORMATION ReturnInfo,
570   PULONG BytesReceived)
571 /*
572  * FUNCTION: Attempts to receive a datagram from a remote address
573  * ARGUMENTS:
574  *     Request       = Pointer to TDI request
575  *     ConnInfo      = Pointer to connection information
576  *     Buffer        = Pointer to NDIS buffer chain to store received data
577  *     ReceiveLength = Maximum size to use of buffer (0 if all can be used)
578  *     ReceiveFlags  = Receive flags (None, Normal, Peek)
579  *     ReturnInfo    = Pointer to structure for return information
580  *     BytesReceive  = Pointer to structure for number of bytes received
581  * RETURNS:
582  *     Status of operation
583  * NOTES:
584  *     This is the high level interface for receiving datagrams
585  */
586 {
587   PADDRESS_FILE AddrFile;
588   KIRQL OldIrql;
589   NTSTATUS Status;
590   PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
591
592   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
593
594   AddrFile = Request->Handle.AddressHandle;
595
596   KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
597
598   if (AF_IS_VALID(AddrFile)) {
599     ReceiveRequest = ExAllocatePool(NonPagedPool, sizeof(DATAGRAM_RECEIVE_REQUEST));
600     if (ReceiveRequest) {
601       /* Initialize a receive request */
602
603       /* Extract the remote address filter from the request (if any) */
604       if (((ConnInfo->RemoteAddressLength != 0)) && (ConnInfo->RemoteAddress)) {
605         Status = AddrGetAddress(ConnInfo->RemoteAddress,
606           &ReceiveRequest->RemoteAddress,
607           &ReceiveRequest->RemotePort,
608           &AddrFile->AddrCache);
609         if (!NT_SUCCESS(Status)) {
610           KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
611           ExFreePool(ReceiveRequest);
612           return Status;
613         }
614       } else {
615         ReceiveRequest->RemotePort    = 0;
616         ReceiveRequest->RemoteAddress = NULL;
617       }
618       ReceiveRequest->ReturnInfo = ReturnInfo;
619       ReceiveRequest->Buffer     = Buffer;
620       /* If ReceiveLength is 0, the whole buffer is available to us */
621       ReceiveRequest->BufferSize = (ReceiveLength == 0) ?
622         MmGetMdlByteCount(Buffer) : ReceiveLength;
623       ReceiveRequest->Complete   = Request->RequestNotifyObject;
624       ReceiveRequest->Context    = Request->RequestContext;
625
626       /* Queue receive request */
627       InsertTailList(&AddrFile->ReceiveQueue, &ReceiveRequest->ListEntry);
628
629       /* Reference address file and set pending receive request flag */
630       AddrFile->RefCount++;
631       AF_SET_PENDING(AddrFile, AFF_RECEIVE);
632
633       KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
634
635       TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
636
637       return STATUS_PENDING;
638     } else
639       Status = STATUS_INSUFFICIENT_RESOURCES;
640   } else
641     Status = STATUS_INVALID_ADDRESS;
642
643   KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
644
645   TI_DbgPrint(MAX_TRACE, ("Leaving with errors (0x%X).\n", Status));
646
647   return Status;
648 }
649
650
651 NTSTATUS DGStartup(
652   VOID)
653 /*
654  * FUNCTION: Initializes the datagram subsystem
655  * RETURNS:
656  *     Status of operation
657  */
658 {
659   InitializeListHead(&DGPendingListHead);
660
661   KeInitializeSpinLock(&DGPendingListLock);
662
663   ExInitializeWorkItem(&DGWorkItem, DatagramWorker, NULL);
664
665   return STATUS_SUCCESS;
666 }
667
668
669 NTSTATUS DGShutdown(
670   VOID)
671 /*
672  * FUNCTION: Shuts down the datagram subsystem
673  * RETURNS:
674  *     Status of operation
675  */
676 {
677   return STATUS_SUCCESS;
678 }
679
680
681 /* EOF */