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