dde71b9adcc08b188acab0913317b2c23b272d6c
[reactos.git] / drivers / net / tcpip / tcpip / main.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        tcpip/main.c
5  * PURPOSE:     Driver entry point
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 #include <tcpip.h>
11 #include <dispatch.h>
12 #include <fileobjs.h>
13 #include <datagram.h>
14 #include <loopback.h>
15 #include <rawip.h>
16 #include <udp.h>
17 #include <tcp.h>
18
19 //#define _USE_NE2000
20
21 #ifdef DBG
22
23 /* See debug.h for debug/trace constants */
24 #ifdef _USE_NE2000
25 DWORD DebugTraceLevel = MID_TRACE;
26 //DWORD DebugTraceLevel = (MAX_TRACE + DEBUG_DATALINK);
27 #else
28 DWORD DebugTraceLevel = MIN_TRACE;
29 //DWORD DebugTraceLevel = MAX_TRACE;
30 //DWORD DebugTraceLevel = DEBUG_ULTRA;
31 #endif
32
33 #endif /* DBG */
34
35 PDEVICE_OBJECT TCPDeviceObject   = NULL;
36 PDEVICE_OBJECT UDPDeviceObject   = NULL;
37 PDEVICE_OBJECT IPDeviceObject    = NULL;
38 PDEVICE_OBJECT RawIPDeviceObject = NULL;
39 NDIS_HANDLE GlobalPacketPool     = NULL;
40 NDIS_HANDLE GlobalBufferPool     = NULL;
41 TDIEntityID *EntityList          = NULL;
42 ULONG EntityCount                = 0;
43 UDP_STATISTICS UDPStats;
44
45
46 VOID TiWriteErrorLog(
47     PDRIVER_OBJECT DriverContext,
48     NTSTATUS ErrorCode,
49     ULONG UniqueErrorValue,
50     NTSTATUS FinalStatus,
51     PWSTR String,
52     ULONG DumpDataCount,
53     PULONG DumpData)
54 /*
55  * FUNCTION: Writes an error log entry
56  * ARGUMENTS:
57  *     DriverContext    = Pointer to the driver or device object
58  *     ErrorCode        = An error code to put in the log entry
59  *     UniqueErrorValue = UniqueErrorValue in the error log packet
60  *     FinalStatus      = FinalStatus in the error log packet
61  *     String           = If not NULL, a pointer to a string to put in log entry
62  *     DumpDataCount    = Number of ULONGs of dump data
63  *     DumpData         = Pointer to dump data for the log entry
64  */
65 {
66 #ifdef _MSC_VER
67     PIO_ERROR_LOG_PACKET LogEntry;
68     UCHAR EntrySize;
69     ULONG StringSize;
70     PUCHAR pString;
71     static WCHAR DriverName[] = L"TCP/IP";
72
73     EntrySize = sizeof(IO_ERROR_LOG_PACKET) + 
74         (DumpDataCount * sizeof(ULONG)) + sizeof(DriverName);
75
76     if (String) {
77         StringSize = (wcslen(String) * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
78         EntrySize += (UCHAR)StringSize;
79     }
80
81     LogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
82                 DriverContext, EntrySize);
83
84     if (LogEntry) {
85         LogEntry->MajorFunctionCode = -1;
86         LogEntry->RetryCount        = -1;
87         LogEntry->DumpDataSize      = (USHORT)(DumpDataCount * sizeof(ULONG));
88         LogEntry->NumberOfStrings   = (String == NULL) ? 1 : 2;
89         LogEntry->StringOffset      = sizeof(IO_ERROR_LOG_PACKET) + (DumpDataCount-1) * sizeof(ULONG);
90         LogEntry->EventCategory     = 0;
91         LogEntry->ErrorCode         = ErrorCode;
92         LogEntry->UniqueErrorValue  = UniqueErrorValue;
93         LogEntry->FinalStatus       = FinalStatus;
94         LogEntry->SequenceNumber    = -1;
95         LogEntry->IoControlCode     = 0;
96
97         if (DumpDataCount)
98             RtlCopyMemory(LogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
99
100         pString = ((PUCHAR)LogEntry) + LogEntry->StringOffset;
101         RtlCopyMemory(pString, DriverName, sizeof(DriverName));
102         pString += sizeof(DriverName);
103
104         if (String)
105             RtlCopyMemory(pString, String, StringSize);
106
107         IoWriteErrorLogEntry(LogEntry);
108     }
109 #endif
110 }
111
112
113 NTSTATUS TiGetProtocolNumber(
114   PUNICODE_STRING FileName,
115   PULONG Protocol)
116 /*
117  * FUNCTION: Returns the protocol number from a file name
118  * ARGUMENTS:
119  *     FileName = Pointer to string with file name
120  *     Protocol = Pointer to buffer to put protocol number in
121  * RETURNS:
122  *     Status of operation
123  */
124 {
125   UNICODE_STRING us;
126   NTSTATUS Status;
127   ULONG Value;
128   PWSTR Name;
129
130   TI_DbgPrint(MAX_TRACE, ("Called. FileName (%wZ).\n", FileName));
131
132   Name = FileName->Buffer;
133
134   if (*Name++ != (WCHAR)L'\\')
135     return STATUS_UNSUCCESSFUL;
136
137   if (*Name == (WCHAR)NULL)
138     return STATUS_UNSUCCESSFUL;
139
140   RtlInitUnicodeString(&us, Name);
141
142   Status = RtlUnicodeStringToInteger(&us, 10, &Value);
143   if (!NT_SUCCESS(Status) || ((Value > 255)))
144     return STATUS_UNSUCCESSFUL;
145
146   *Protocol = Value;
147
148   return STATUS_SUCCESS;
149 }
150
151
152 /*
153  * FUNCTION: Creates a file object
154  * ARGUMENTS:
155  *     DeviceObject = Pointer to a device object for this driver
156  *     Irp          = Pointer to a I/O request packet
157  * RETURNS:
158  *     Status of the operation
159  */
160 NTSTATUS TiCreateFileObject(
161   PDEVICE_OBJECT DeviceObject,
162   PIRP Irp)
163 {
164   PFILE_FULL_EA_INFORMATION EaInfo;
165   PTRANSPORT_CONTEXT Context;
166   PIO_STACK_LOCATION IrpSp;
167   PTA_ADDRESS_IP Address;
168   TDI_REQUEST Request;
169   PVOID ClientContext;
170   NTSTATUS Status;
171   ULONG Protocol;
172
173   TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
174
175   EaInfo = Irp->AssociatedIrp.SystemBuffer;
176 CP
177   /* Parameter check */
178   if (!EaInfo) {
179     TI_DbgPrint(MIN_TRACE, ("No EA information in IRP.\n"));
180     return STATUS_INVALID_PARAMETER;
181   }
182 CP
183   /* Allocate resources here. We release them again if something failed */
184   Context = ExAllocatePool(NonPagedPool, sizeof(TRANSPORT_CONTEXT));
185   if (!Context) {
186     TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
187     return STATUS_INSUFFICIENT_RESOURCES;
188   }
189 CP
190   Context->RefCount   = 1;
191   Context->CancelIrps = FALSE;
192   KeInitializeEvent(&Context->CleanupEvent, NotificationEvent, FALSE);
193 CP
194   IrpSp = IoGetCurrentIrpStackLocation(Irp);
195   IrpSp->FileObject->FsContext = Context;
196   Request.RequestContext       = Irp;
197 CP
198   /* Branch to the right handler */
199   if ((EaInfo->EaNameLength == TDI_TRANSPORT_ADDRESS_LENGTH) && 
200     (RtlCompareMemory(&EaInfo->EaName, TdiTransportAddress,
201      TDI_TRANSPORT_ADDRESS_LENGTH) == TDI_TRANSPORT_ADDRESS_LENGTH)) {
202     /* This is a request to open an address */
203 CP
204     /* Parameter checks */
205     Address = (PTA_ADDRESS_IP)(EaInfo->EaName + EaInfo->EaNameLength);
206     if ((EaInfo->EaValueLength < sizeof(TA_ADDRESS_IP)) ||
207       (Address->TAAddressCount != 1) ||
208       (Address->Address[0].AddressLength < TDI_ADDRESS_LENGTH_IP) ||
209       (Address->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)) {
210       TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
211       ExFreePool(Context);
212       return STATUS_INVALID_PARAMETER;
213     }
214 CP
215     /* Open address file object */
216
217     /* Protocol depends on device object so find the protocol */
218     if (DeviceObject == TCPDeviceObject)
219       Protocol = IPPROTO_TCP;
220     else if (DeviceObject == UDPDeviceObject)
221       Protocol = IPPROTO_UDP;
222     else if (DeviceObject == IPDeviceObject)
223       Protocol = IPPROTO_RAW;
224     else if (DeviceObject == RawIPDeviceObject) {
225       Status = TiGetProtocolNumber(&IrpSp->FileObject->FileName, &Protocol);
226       if (!NT_SUCCESS(Status)) {
227         TI_DbgPrint(MIN_TRACE, ("Raw IP protocol number is invalid.\n"));
228         ExFreePool(Context);
229         return STATUS_INVALID_PARAMETER;
230       }
231     } else {
232       TI_DbgPrint(MIN_TRACE, ("Invalid device object at (0x%X).\n", DeviceObject));
233       ExFreePool(Context);
234       return STATUS_INVALID_PARAMETER;
235     }
236 CP
237     Status = FileOpenAddress(&Request, Address, Protocol, NULL);
238     if (NT_SUCCESS(Status)) {
239       IrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
240       Context->Handle.AddressHandle = Request.Handle.AddressHandle;
241     }
242 CP
243   } else if ((EaInfo->EaNameLength == TDI_CONNECTION_CONTEXT_LENGTH) && 
244     (RtlCompareMemory(&EaInfo->EaName, TdiConnectionContext,
245      TDI_CONNECTION_CONTEXT_LENGTH) == TDI_CONNECTION_CONTEXT_LENGTH)) {
246     /* This is a request to open a connection endpoint */
247 CP
248     /* Parameter checks */
249
250     if (EaInfo->EaValueLength < sizeof(PVOID)) {
251       TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
252       ExFreePool(Context);
253       return STATUS_INVALID_PARAMETER;
254     }
255
256     /* Can only do connection oriented communication using TCP */
257
258     if (DeviceObject != TCPDeviceObject) {
259       TI_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
260       ExFreePool(Context);
261       return STATUS_INVALID_PARAMETER;
262     }
263
264     ClientContext = *((PVOID*)(EaInfo->EaName + EaInfo->EaNameLength));
265
266     /* Open connection endpoint file object */
267
268     Status = FileOpenConnection(&Request, ClientContext);
269     if (NT_SUCCESS(Status)) {
270       IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
271       Context->Handle.ConnectionContext = Request.Handle.ConnectionContext;
272     }
273   } else {
274     /* This is a request to open a control connection */
275
276     TI_DbgPrint(MIN_TRACE, ("Control connections are not implemented yet\n"));
277
278     Status = STATUS_NOT_IMPLEMENTED;
279   }
280
281   if (!NT_SUCCESS(Status))
282     ExFreePool(Context);
283
284   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
285
286   return Status;
287 }
288
289
290 VOID TiCleanupFileObjectComplete(
291   PVOID Context,
292   NTSTATUS Status)
293 /*
294  * FUNCTION: Completes an object cleanup IRP I/O request
295  * ARGUMENTS:
296  *     Context = Pointer to the IRP for this request
297  *     Status  = Final status of the operation
298  */
299 {
300   PIRP Irp;
301   PIO_STACK_LOCATION IrpSp;
302   PTRANSPORT_CONTEXT TranContext;
303   KIRQL OldIrql;
304
305   Irp         = (PIRP)Context;
306   IrpSp       = IoGetCurrentIrpStackLocation(Irp);
307   TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
308
309   Irp->IoStatus.Status = Status;
310   
311   IoAcquireCancelSpinLock(&OldIrql);
312
313   /* Remove the initial reference provided at object creation time */
314   TranContext->RefCount--;
315
316 #ifdef DBG
317   if (TranContext->RefCount != 0)
318     TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount is %i, should be 0.\n", TranContext->RefCount));
319 #endif
320
321   KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
322
323   IoReleaseCancelSpinLock(OldIrql);
324 }
325
326
327 /*
328  * FUNCTION: Releases resources used by a file object
329  * ARGUMENTS:
330  *     DeviceObject = Pointer to a device object for this driver
331  *     Irp          = Pointer to a I/O request packet
332  * RETURNS:
333  *     Status of the operation
334  * NOTES:
335  *     This function does not pend
336  */
337 NTSTATUS TiCleanupFileObject(
338   PDEVICE_OBJECT DeviceObject,
339   PIRP Irp)
340 {
341   PIO_STACK_LOCATION IrpSp;
342   PTRANSPORT_CONTEXT Context;
343   TDI_REQUEST Request;
344   NTSTATUS Status;
345   KIRQL OldIrql;
346
347   IrpSp   = IoGetCurrentIrpStackLocation(Irp);
348   Context = IrpSp->FileObject->FsContext;    
349   if (!Context) {
350     TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
351     return STATUS_INVALID_PARAMETER;
352   }
353
354   IoAcquireCancelSpinLock(&OldIrql);
355
356   Context->CancelIrps = TRUE;
357   KeResetEvent(&Context->CleanupEvent);
358
359   IoReleaseCancelSpinLock(OldIrql);
360
361   Request.RequestNotifyObject = TiCleanupFileObjectComplete;
362   Request.RequestContext      = Irp;
363
364   switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
365   case TDI_TRANSPORT_ADDRESS_FILE:
366     Request.Handle.AddressHandle = Context->Handle.AddressHandle;
367     Status = FileCloseAddress(&Request);
368     break;
369
370   case TDI_CONNECTION_FILE:
371     Request.Handle.ConnectionContext = Context->Handle.ConnectionContext;
372     Status = FileCloseConnection(&Request);
373     break;
374
375   case TDI_CONTROL_CHANNEL_FILE:
376     Request.Handle.ControlChannel = Context->Handle.ControlChannel;
377     Status = FileCloseControlChannel(&Request);
378     break;
379
380   default:
381     /* This should never happen */
382
383     TI_DbgPrint(MIN_TRACE, ("Unknown transport context.\n"));
384
385     IoAcquireCancelSpinLock(&OldIrql);
386     Context->CancelIrps = FALSE;
387     IoReleaseCancelSpinLock(OldIrql);
388
389     return STATUS_INVALID_PARAMETER;
390   }
391
392   if (Status != STATUS_PENDING)
393     TiCleanupFileObjectComplete(Irp, Status);
394   
395   KeWaitForSingleObject(&Context->CleanupEvent,
396     UserRequest, KernelMode, FALSE, NULL);
397   
398   return Irp->IoStatus.Status;
399 }
400
401
402 NTSTATUS
403 #ifndef _MSC_VER
404 STDCALL
405 #endif
406 TiDispatchOpenClose(
407   PDEVICE_OBJECT DeviceObject,
408   PIRP Irp)
409 /*
410  * FUNCTION: Main dispath routine
411  * ARGUMENTS:
412  *     DeviceObject = Pointer to a device object for this driver
413  *     Irp          = Pointer to a I/O request packet
414  * RETURNS:
415  *     Status of the operation
416  */
417 {
418   PIO_STACK_LOCATION IrpSp;
419   NTSTATUS Status;
420   PTRANSPORT_CONTEXT Context;
421
422   TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
423
424   IoMarkIrpPending(Irp);
425   Irp->IoStatus.Status      = STATUS_PENDING;
426   Irp->IoStatus.Information = 0;
427
428   IrpSp = IoGetCurrentIrpStackLocation(Irp);
429
430   switch (IrpSp->MajorFunction) {
431   /* Open an address file, connection endpoint, or control connection */
432   case IRP_MJ_CREATE:
433     Status = TiCreateFileObject(DeviceObject, Irp);
434     break;
435
436   /* Close an address file, connection endpoint, or control connection */
437   case IRP_MJ_CLOSE:
438     Context = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
439     if (Context)
440         ExFreePool(Context);
441     Status = STATUS_SUCCESS;
442     break;
443
444   /* Release resources bound to an address file, connection endpoint, 
445      or control connection */
446   case IRP_MJ_CLEANUP:
447     Status = TiCleanupFileObject(DeviceObject, Irp);
448     break;
449
450   default:
451     Status = STATUS_INVALID_DEVICE_REQUEST;
452   }
453
454   if (Status != STATUS_PENDING) {
455     IrpSp->Control &= ~SL_PENDING_RETURNED;
456     Irp->IoStatus.Status = Status;
457
458     TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
459
460     IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
461   }
462
463   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
464
465   return Status;
466 }
467
468
469 NTSTATUS
470 #ifndef _MSC_VER
471 STDCALL
472 #endif
473 TiDispatchInternal(
474   PDEVICE_OBJECT DeviceObject,
475   PIRP Irp)
476 /*
477  * FUNCTION: Internal IOCTL dispatch routine
478  * ARGUMENTS:
479  *     DeviceObject = Pointer to a device object for this driver
480  *     Irp          = Pointer to a I/O request packet
481  * RETURNS:
482  *     Status of the operation
483  */
484 {
485         NTSTATUS Status;
486   PIO_STACK_LOCATION IrpSp;
487
488   IrpSp = IoGetCurrentIrpStackLocation(Irp);
489
490   TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X) MN (%d).\n",
491     DeviceObject, Irp, IrpSp->MinorFunction));
492
493   Irp->IoStatus.Status      = STATUS_SUCCESS;
494   Irp->IoStatus.Information = 0;
495
496   switch (IrpSp->MinorFunction) {
497   case TDI_RECEIVE:
498     Status = DispTdiReceive(Irp);
499     break;
500
501   case TDI_RECEIVE_DATAGRAM:
502     Status = DispTdiReceiveDatagram(Irp);
503     break;
504
505   case TDI_SEND:
506     Status = DispTdiSend(Irp);
507     break;
508
509   case TDI_SEND_DATAGRAM:
510     Status = DispTdiSendDatagram(Irp);
511     break;
512
513   case TDI_ACCEPT:
514     Status = DispTdiAccept(Irp);
515     break;
516
517   case TDI_LISTEN:
518     Status = DispTdiListen(Irp);
519     break;
520
521   case TDI_CONNECT:
522     Status = DispTdiConnect(Irp);
523     break;
524
525   case TDI_DISCONNECT:
526     Status = DispTdiDisconnect(Irp);
527     break;
528
529   case TDI_ASSOCIATE_ADDRESS:
530     Status = DispTdiAssociateAddress(Irp);
531     break;
532
533   case TDI_DISASSOCIATE_ADDRESS:
534     Status = DispTdiDisassociateAddress(Irp);
535     break;
536
537   case TDI_QUERY_INFORMATION:
538     Status = DispTdiQueryInformation(DeviceObject, Irp);
539     break;
540
541   case TDI_SET_INFORMATION:
542     Status = DispTdiSetInformation(Irp);
543     break;
544
545   case TDI_SET_EVENT_HANDLER:
546     Status = DispTdiSetEventHandler(Irp);
547     break;
548
549   case TDI_ACTION:
550     Status = STATUS_SUCCESS;
551     break;
552
553   /* An unsupported IOCTL code was submitted */
554   default:
555     Status = STATUS_INVALID_DEVICE_REQUEST;
556   }
557
558   if (Status != STATUS_PENDING) {
559     Irp->IoStatus.Status = Status;
560
561     TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
562
563     IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
564   }
565
566   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
567
568         return Status;
569 }
570
571
572 NTSTATUS
573 #ifndef _MSC_VER
574 STDCALL
575 #endif
576 TiDispatch(
577   PDEVICE_OBJECT DeviceObject,
578   PIRP Irp)
579 /*
580  * FUNCTION: Dispatch routine for IRP_MJ_DEVICE_CONTROL requests
581  * ARGUMENTS:
582  *     DeviceObject = Pointer to a device object for this driver
583  *     Irp          = Pointer to a I/O request packet
584  * RETURNS:
585  *     Status of the operation
586  */
587 {
588   NTSTATUS Status;
589   PIO_STACK_LOCATION IrpSp;
590
591   TI_DbgPrint(DEBUG_IRP, ("Called. IRP is at (0x%X).\n", Irp));
592
593   Irp->IoStatus.Information = 0;
594
595   IrpSp  = IoGetCurrentIrpStackLocation(Irp);
596 #ifdef _MSC_VER
597   Status = TdiMapUserRequest(DeviceObject, Irp, IrpSp);
598   if (NT_SUCCESS(Status)) {
599     TiDispatchInternal(DeviceObject, Irp);
600     Status = STATUS_PENDING;
601   } else {
602 #else
603   if (TRUE) {
604 #endif
605     /* See if this request is TCP/IP specific */
606     switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
607     case IOCTL_TCP_QUERY_INFORMATION_EX:
608       Status = DispTdiQueryInformationEx(Irp, IrpSp);
609       break;
610
611     case IOCTL_TCP_SET_INFORMATION_EX:
612       Status = DispTdiSetInformationEx(Irp, IrpSp);
613       break;
614
615     default:
616       TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n",
617           IrpSp->Parameters.DeviceIoControl.IoControlCode));
618       Status = STATUS_NOT_IMPLEMENTED;
619       break;
620     }
621   }
622
623   if (Status != STATUS_PENDING) {
624     Irp->IoStatus.Status = Status;
625
626     TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
627
628     IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
629   }
630
631   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
632
633   return Status;
634 }
635
636
637 VOID TiUnload(
638   PDRIVER_OBJECT DriverObject)
639 /*
640  * FUNCTION: Unloads the driver
641  * ARGUMENTS:
642  *     DriverObject = Pointer to driver object created by the system
643  */
644 {
645 #ifdef DBG
646   KIRQL OldIrql;
647
648   KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
649   if (!IsListEmpty(&AddressFileListHead)) {
650     TI_DbgPrint(MIN_TRACE, ("Open address file objects exists.\n"));
651   }
652   KeReleaseSpinLock(&AddressFileListLock, OldIrql);
653 #endif
654
655   /* Unregister loopback adapter */
656   LoopUnregisterAdapter(NULL);
657
658   /* Unregister protocol with NDIS */
659   LANUnregisterProtocol();
660
661   /* Shutdown transport level protocol subsystems */
662   TCPShutdown();
663   UDPShutdown();
664   RawIPShutdown();
665   DGShutdown();
666
667   /* Shutdown network level protocol subsystem */
668   IPShutdown();
669
670   /* Free NDIS buffer descriptors */
671   if (GlobalBufferPool)
672     NdisFreeBufferPool(GlobalBufferPool);
673
674   /* Free NDIS packet descriptors */
675   if (GlobalPacketPool)
676     NdisFreePacketPool(GlobalPacketPool);
677
678   /* Release all device objects */
679
680   if (TCPDeviceObject)
681     IoDeleteDevice(TCPDeviceObject);
682
683   if (UDPDeviceObject)
684     IoDeleteDevice(UDPDeviceObject);
685
686   if (RawIPDeviceObject)
687     IoDeleteDevice(RawIPDeviceObject);
688
689   if (IPDeviceObject)
690     IoDeleteDevice(IPDeviceObject);
691
692   if (EntityList)
693     ExFreePool(EntityList);
694
695   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
696 }
697
698
699 NTSTATUS
700 #ifndef _MSC_VER
701 STDCALL
702 #endif
703 DriverEntry(
704   PDRIVER_OBJECT DriverObject,
705   PUNICODE_STRING RegistryPath)
706 /*
707  * FUNCTION: Main driver entry point
708  * ARGUMENTS:
709  *     DriverObject = Pointer to a driver object for this driver
710  *     RegistryPath = Registry node for configuration parameters
711  * RETURNS:
712  *     Status of driver initialization
713  */
714 {
715   NTSTATUS Status;
716   UNICODE_STRING strDeviceName;
717   STRING strNdisDeviceName;
718   NDIS_STATUS NdisStatus;
719   PLAN_ADAPTER Adapter;
720   NDIS_STRING DeviceName;
721
722   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
723
724   /* FIXME: Create symbolic links in Win32 namespace */
725
726   /* Create IP device object */
727   RtlInitUnicodeStringFromLiteral(&strDeviceName, DD_IP_DEVICE_NAME);
728   Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
729     FILE_DEVICE_NETWORK, 0, FALSE, &IPDeviceObject);
730   if (!NT_SUCCESS(Status)) {
731     TI_DbgPrint(MIN_TRACE, ("Failed to create IP device object. Status (0x%X).\n", Status));
732     return Status;
733   }
734
735   /* Create RawIP device object */
736   RtlInitUnicodeStringFromLiteral(&strDeviceName, DD_RAWIP_DEVICE_NAME);
737   Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
738     FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject);
739   if (!NT_SUCCESS(Status)) {
740     TI_DbgPrint(MIN_TRACE, ("Failed to create RawIP device object. Status (0x%X).\n", Status));
741     TiUnload(DriverObject);
742     return Status;
743   }
744
745   /* Create UDP device object */
746   RtlInitUnicodeStringFromLiteral(&strDeviceName, DD_UDP_DEVICE_NAME);
747   Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
748     FILE_DEVICE_NETWORK, 0, FALSE, &UDPDeviceObject);
749   if (!NT_SUCCESS(Status)) {
750     TI_DbgPrint(MIN_TRACE, ("Failed to create UDP device object. Status (0x%X).\n", Status));
751     TiUnload(DriverObject);
752     return Status;
753   }
754
755   /* Create TCP device object */
756   RtlInitUnicodeStringFromLiteral(&strDeviceName, DD_TCP_DEVICE_NAME);
757   Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
758     FILE_DEVICE_NETWORK, 0, FALSE, &TCPDeviceObject);
759   if (!NT_SUCCESS(Status)) {
760     TI_DbgPrint(MIN_TRACE, ("Failed to create TCP device object. Status (0x%X).\n", Status));
761     TiUnload(DriverObject);
762     return Status;
763   }
764
765   /* Allocate NDIS packet descriptors */
766   NdisAllocatePacketPool(&NdisStatus, &GlobalPacketPool, 100, sizeof(PACKET_CONTEXT));
767   if (NdisStatus != NDIS_STATUS_SUCCESS) {
768     TiUnload(DriverObject);
769     return STATUS_INSUFFICIENT_RESOURCES;
770   }
771
772   /* Allocate NDIS buffer descriptors */
773   NdisAllocateBufferPool(&NdisStatus, &GlobalBufferPool, 100);
774   if (NdisStatus != NDIS_STATUS_SUCCESS) {
775     TiUnload(DriverObject);
776     return STATUS_INSUFFICIENT_RESOURCES;
777   }
778
779   /* Initialize address file list and protecting spin lock */
780   InitializeListHead(&AddressFileListHead);
781   KeInitializeSpinLock(&AddressFileListLock);
782
783   /* Initialize connection endpoint list and protecting spin lock */
784   InitializeListHead(&ConnectionEndpointListHead);
785   KeInitializeSpinLock(&ConnectionEndpointListLock);
786
787   /* Initialize interface list and protecting spin lock */
788   InitializeListHead(&InterfaceListHead);
789   KeInitializeSpinLock(&InterfaceListLock);
790
791   /* Initialize network level protocol subsystem */
792   IPStartup(DriverObject, RegistryPath);
793
794   /* Initialize transport level protocol subsystems */
795   DGStartup();
796   RawIPStartup();
797   UDPStartup();
798   TCPStartup();
799
800   /* Register protocol with NDIS */
801   RtlInitString(&strNdisDeviceName, IP_DEVICE_NAME);
802   Status = LANRegisterProtocol(&strNdisDeviceName);
803   if (!NT_SUCCESS(Status)) {
804           TiWriteErrorLog(
805       DriverObject,
806       EVENT_TRANSPORT_REGISTER_FAILED,
807       TI_ERROR_DRIVERENTRY,
808       Status,
809       NULL,
810       0,
811       NULL);
812     TiUnload(DriverObject);
813     return Status;
814   }
815
816   /* Open loopback adapter */
817   if (!NT_SUCCESS(LoopRegisterAdapter(NULL, NULL))) {
818     TI_DbgPrint(MIN_TRACE, ("Failed to create loopback adapter. Status (0x%X).\n", Status));
819     TiUnload(DriverObject);
820     return STATUS_INSUFFICIENT_RESOURCES;
821   }
822
823 /* Open underlying adapter(s) we are bound to */
824
825   /* FIXME: Get binding information from registry */
826
827   /* Put your own NDIS adapter device name here */
828 #ifdef _USE_NE2000
829   /* ReactOS */
830   NdisInitUnicodeString(&DeviceName, L"\\Device\\ne2000");
831
832   /* NT4 style */
833   //NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1");
834
835   /* NT5 style */
836   //NdisInitUnicodeString(&DeviceName, L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}");
837
838   NdisStatus = LANRegisterAdapter(&DeviceName, &Adapter);
839
840   /* Skip network adapter if it does not exist */
841   if (!NT_SUCCESS(NdisStatus)) {
842     TI_DbgPrint(MIN_TRACE, ("Failed to intialize adapter. Status (0x%X).\n", Status));
843           TiWriteErrorLog(
844       DriverObject,
845       EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
846       TI_ERROR_DRIVERENTRY,
847       NdisStatus,
848       NULL,
849       0,
850       NULL);
851     TiUnload(DriverObject);
852     return STATUS_DEVICE_DOES_NOT_EXIST;
853   }
854 #endif
855   /* Setup network layer and transport layer entities */
856   EntityList = ExAllocatePool(NonPagedPool, sizeof(TDIEntityID) * 2);
857   if (!NT_SUCCESS(Status)) {
858     TiUnload(DriverObject);
859     return STATUS_INSUFFICIENT_RESOURCES;
860   }
861
862   EntityList[0].tei_entity   = CL_NL_ENTITY;
863   EntityList[0].tei_instance = 0;
864   EntityList[1].tei_entity   = CL_TL_ENTITY;
865   EntityList[1].tei_instance = 0;
866   EntityCount = 2;
867
868   /* Use direct I/O */
869   IPDeviceObject->Flags    |= DO_DIRECT_IO;
870   RawIPDeviceObject->Flags |= DO_DIRECT_IO;
871   UDPDeviceObject->Flags   |= DO_DIRECT_IO;
872   TCPDeviceObject->Flags   |= DO_DIRECT_IO;
873
874   /* Initialize the driver object with this driver's entry points */
875   DriverObject->MajorFunction[IRP_MJ_CREATE]  = TiDispatchOpenClose;
876   DriverObject->MajorFunction[IRP_MJ_CLOSE]   = TiDispatchOpenClose;
877   DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TiDispatchOpenClose;
878   DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TiDispatchInternal;
879   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TiDispatch;
880
881   DriverObject->DriverUnload = (PDRIVER_UNLOAD)TiUnload;
882
883   return STATUS_SUCCESS;
884 }
885
886
887 VOID
888 #ifndef _MSC_VER
889 STDCALL
890 #endif
891 IPAddInterface(
892         DWORD   Unknown0,
893         DWORD   Unknown1,
894         DWORD   Unknown2,
895         DWORD   Unknown3,
896         DWORD   Unknown4)
897 {
898     UNIMPLEMENTED
899 }
900
901
902 VOID
903 #ifndef _MSC_VER
904 STDCALL
905 #endif
906 IPDelInterface(
907         DWORD   Unknown0)
908 {
909     UNIMPLEMENTED
910 }
911
912
913 VOID
914 #ifndef _MSC_VER
915 STDCALL
916 #endif
917 LookupRoute(
918         DWORD   Unknown0,
919         DWORD   Unknown1)
920 {
921     UNIMPLEMENTED
922 }
923
924 /* EOF */