2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TDI test driver
5 * PURPOSE: Testing TDI drivers
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
15 /* See debug.h for debug/trace constants */
16 DWORD DebugTraceLevel = MIN_TRACE;
21 HANDLE TdiTransport = 0;
22 PFILE_OBJECT TdiTransportObject = NULL;
27 KEVENT SendThreadEvent;
29 KEVENT ReceiveThreadEvent;
30 PVOID ReceiveThreadObject;
31 PVOID SendThreadObject;
36 PDEVICE_OBJECT DeviceObject,
37 PIO_STATUS_BLOCK IoStatusBlock,
40 * FUNCTION: Calls a transport driver device
42 * Irp = Pointer to I/O Request Packet
43 * DeviceObject = Pointer to device object to call
44 * IoStatusBlock = Address of buffer with I/O status block
45 * CanCancel = TRUE if the IRP can be cancelled, FALSE if not
49 * All requests are completed synchronously. A request may be cancelled
55 Events[0] = &StopEvent;
58 KeInitializeEvent(&Event, NotificationEvent, FALSE);
59 Irp->UserEvent = &Event;
60 Irp->UserIosb = IoStatusBlock;
61 Status = IoCallDriver(DeviceObject, Irp);
62 if (Status == STATUS_PENDING) {
64 Status = KeWaitForMultipleObjects(2,
73 if (KeReadStateEvent(&StopEvent) != 0) {
74 if (IoCancelIrp(Irp)) {
75 TDI_DbgPrint(MAX_TRACE, ("Cancelled IRP.\n"));
77 TDI_DbgPrint(MIN_TRACE, ("Could not cancel IRP.\n"));
79 return STATUS_CANCELLED;
82 Status = KeWaitForSingleObject(&Event,
89 return (Status == STATUS_SUCCESS)? IoStatusBlock->Status : STATUS_SUCCESS;
93 NTSTATUS TdiOpenDevice(
96 PFILE_FULL_EA_INFORMATION EaInfo,
100 * FUNCTION: Opens a device
102 * Protocol = Pointer to buffer with name of device
103 * EaLength = Length of EA information
104 * EaInfo = Pointer to buffer with EA information
105 * Handle = Address of buffer to place device handle
106 * Object = Address of buffer to place device object
108 * Status of operation
111 OBJECT_ATTRIBUTES Attr;
112 IO_STATUS_BLOCK Iosb;
116 RtlInitUnicodeString(&Name, Protocol);
117 InitializeObjectAttributes(&Attr, /* Attribute buffer */
118 &Name, /* Device name */
119 OBJ_CASE_INSENSITIVE, /* Attributes */
120 NULL, /* Root directory */
121 NULL); /* Security descriptor */
123 Status = ZwCreateFile(Handle, /* Return file handle */
124 GENERIC_READ | GENERIC_WRITE, /* Desired access */
125 &Attr, /* Object attributes */
126 &Iosb, /* IO status */
127 0, /* Initial allocation size */
128 FILE_ATTRIBUTE_NORMAL, /* File attributes */
129 FILE_SHARE_READ | FILE_SHARE_WRITE, /* Share access */
130 FILE_OPEN_IF, /* Create disposition */
131 0, /* Create options */
132 EaInfo, /* EA buffer */
133 EaLength); /* EA length */
134 if (NT_SUCCESS(Status)) {
135 Status = ObReferenceObjectByHandle(*Handle, /* Handle to open file */
136 GENERIC_READ | GENERIC_WRITE, /* Access mode */
137 NULL, /* Object type */
138 KernelMode, /* Access mode */
139 (PVOID*)Object, /* Pointer to object */
140 NULL); /* Handle information */
141 if (!NT_SUCCESS(Status)) {
142 TDI_DbgPrint(MIN_TRACE, ("ObReferenceObjectByHandle() failed with status (0x%X).\n", Status));
146 TDI_DbgPrint(MIN_TRACE, ("ZwCreateFile() failed with status (0x%X)\n", Status));
153 NTSTATUS TdiCloseDevice(
155 PFILE_OBJECT FileObject)
158 ObDereferenceObject(FileObject);
163 return STATUS_SUCCESS;
167 NTSTATUS TdiOpenTransport(
171 PFILE_OBJECT *TransportObject)
173 * FUNCTION: Opens a transport driver
175 * Protocol = Pointer to buffer with name of device
176 * Port = Port number to use
177 * Transport = Address of buffer to place transport device handle
178 * TransportObject = Address of buffer to place transport object
180 * Status of operation
183 PFILE_FULL_EA_INFORMATION EaInfo;
184 PTA_ADDRESS_IP Address;
188 EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
189 TDI_TRANSPORT_ADDRESS_LENGTH +
190 sizeof(TA_ADDRESS_IP);
191 EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, EaLength);
193 TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
194 return STATUS_INSUFFICIENT_RESOURCES;
197 RtlZeroMemory(EaInfo, EaLength);
198 EaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
199 RtlCopyMemory(EaInfo->EaName,
201 TDI_TRANSPORT_ADDRESS_LENGTH);
202 EaInfo->EaValueLength = sizeof(TA_ADDRESS_IP);
203 Address = (PTA_ADDRESS_IP)(EaInfo->EaName + TDI_TRANSPORT_ADDRESS_LENGTH);
204 Address->TAAddressCount = 1;
205 Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
206 Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
207 Address->Address[0].Address[0].sin_port = WH2N(Port);
208 Address->Address[0].Address[0].in_addr = 0;
209 Status = TdiOpenDevice(Protocol,
220 NTSTATUS TdiQueryDeviceControl(
221 PFILE_OBJECT FileObject,
224 ULONG InputBufferLength,
226 ULONG OutputBufferLength,
229 * FUNCTION: Queries a device for information
231 * FileObject = Pointer to device object
232 * IoControlCode = I/O control code
233 * InputBuffer = Pointer to buffer with input data
234 * InputBufferLength = Length of InputBuffer
235 * OutputBuffer = Address of buffer to place output data
236 * OutputBufferLength = Length of OutputBuffer
238 * Status of operation
241 PDEVICE_OBJECT DeviceObject;
242 PIO_STACK_LOCATION IoStack;
243 IO_STATUS_BLOCK Iosb;
247 DeviceObject = IoGetRelatedDeviceObject(FileObject);
248 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
258 TDI_DbgPrint(MIN_TRACE, ("IoBuildDeviceIoControlRequest() failed.\n"));
259 return STATUS_INSUFFICIENT_RESOURCES;
262 IoStack = IoGetNextIrpStackLocation(Irp);
263 IoStack->DeviceObject = DeviceObject;
264 IoStack->FileObject = FileObject;
265 Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);
267 *Return = Iosb.Information;
273 NTSTATUS TdiQueryInformationEx(
274 PFILE_OBJECT FileObject,
283 * FUNCTION: Extended query for information
285 * FileObject = Pointer to transport object
287 * Instance = Instance
288 * Class = Entity class
291 * OutputBuffer = Address of buffer to place data
292 * OutputLength = Address of buffer with length of OutputBuffer (updated)
294 * Status of operation
297 TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;
299 RtlZeroMemory(&QueryInfo, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
300 QueryInfo.ID.toi_entity.tei_entity = Entity;
301 QueryInfo.ID.toi_entity.tei_instance = Instance;
302 QueryInfo.ID.toi_class = Class;
303 QueryInfo.ID.toi_type = Type;
304 QueryInfo.ID.toi_id = Id;
306 return TdiQueryDeviceControl(FileObject, /* Transport/connection object */
307 IOCTL_TCP_QUERY_INFORMATION_EX, /* Control code */
308 &QueryInfo, /* Input buffer */
309 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), /* Input buffer length */
310 OutputBuffer, /* Output buffer */
311 *OutputLength, /* Output buffer length */
312 OutputLength); /* Return information */
316 NTSTATUS TdiQueryAddress(
317 PFILE_OBJECT FileObject,
320 * FUNCTION: Queries for a local IP address
322 * FileObject = Pointer to file object
323 * Address = Address of buffer to place local address
325 * Status of operation
329 TDIEntityID *Entities;
332 IPSNMP_INFO SnmpInfo;
333 PIPADDR_ENTRY IpAddress;
335 NTSTATUS Status = STATUS_SUCCESS;
337 TDI_DbgPrint(MAX_TRACE, ("Called\n"));
339 BufferSize = sizeof(TDIEntityID) * 20;
340 Entities = (TDIEntityID*)ExAllocatePool(NonPagedPool, BufferSize);
342 TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
343 return STATUS_INSUFFICIENT_RESOURCES;
346 /* Query device for supported entities */
348 Status = TdiQueryInformationEx(FileObject, /* File object */
349 GENERIC_ENTITY, /* Entity */
350 TL_INSTANCE, /* Instance */
351 INFO_CLASS_GENERIC, /* Entity class */
352 INFO_TYPE_PROVIDER, /* Entity type */
353 ENTITY_LIST_ID, /* Entity id */
354 Entities, /* Output buffer */
355 &BufferSize); /* Output buffer size */
356 if (!NT_SUCCESS(Status)) {
357 TDI_DbgPrint(MIN_TRACE, ("Unable to get list of supported entities (Status = 0x%X).\n", Status));
358 ExFreePool(Entities);
362 /* Locate an IP entity */
363 EntityCount = BufferSize / sizeof(TDIEntityID);
365 TDI_DbgPrint(MAX_TRACE, ("EntityCount = %d\n", EntityCount));
367 for (i = 0; i < EntityCount; i++) {
368 if (Entities[i].tei_entity == CL_NL_ENTITY) {
369 /* Query device for entity type */
371 BufferSize = sizeof(EntityType);
372 Status = TdiQueryInformationEx(FileObject, /* File object */
373 CL_NL_ENTITY, /* Entity */
374 Entities[i].tei_instance, /* Instance */
375 INFO_CLASS_GENERIC, /* Entity class */
376 INFO_TYPE_PROVIDER, /* Entity type */
377 ENTITY_TYPE_ID, /* Entity id */
378 &EntityType, /* Output buffer */
379 &BufferSize); /* Output buffer size */
380 if (!NT_SUCCESS(Status) || (EntityType != CL_NL_IP)) {
381 TDI_DbgPrint(MIN_TRACE, ("Unable to get entity of type IP (Status = 0x%X).\n", Status));
385 /* Query device for SNMP information */
387 BufferSize = sizeof(SnmpInfo);
388 Status = TdiQueryInformationEx(FileObject, /* File object */
389 CL_NL_ENTITY, /* Entity */
390 Entities[i].tei_instance, /* Instance */
391 INFO_CLASS_PROTOCOL, /* Entity class */
392 INFO_TYPE_PROVIDER, /* Entity type */
393 IP_MIB_STATS_ID, /* Entity id */
394 &SnmpInfo, /* Output buffer */
395 &BufferSize); /* Output buffer size */
396 if (!NT_SUCCESS(Status) || (SnmpInfo.NumAddr == 0)) {
397 TDI_DbgPrint(MIN_TRACE, ("Unable to get SNMP information or no IP addresses available (Status = 0x%X).\n", Status));
401 /* Query device for all IP addresses */
403 if (SnmpInfo.NumAddr != 0) {
404 BufferSize = SnmpInfo.NumAddr * sizeof(IPADDR_ENTRY);
405 IpAddress = (PIPADDR_ENTRY)ExAllocatePool(NonPagedPool, BufferSize);
407 TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
411 Status = TdiQueryInformationEx(FileObject, /* File object */
412 CL_NL_ENTITY, /* Entity */
413 Entities[i].tei_instance, /* Instance */
414 INFO_CLASS_PROTOCOL, /* Entity class */
415 INFO_TYPE_PROVIDER, /* Entity type */
416 IP_MIB_ADDRTABLE_ENTRY_ID, /* Entity id */
417 IpAddress, /* Output buffer */
418 &BufferSize); /* Output buffer size */
419 if (!NT_SUCCESS(Status)) {
420 TDI_DbgPrint(MIN_TRACE, ("Unable to get IP address (Status = 0x%X).\n", Status));
421 ExFreePool(IpAddress);
425 if (SnmpInfo.NumAddr != 1) {
426 /* Skip loopback address */
427 *Address = DN2H(((PIPADDR_ENTRY)((ULONG)IpAddress + sizeof(IPADDR_ENTRY)))->Addr);
429 /* Select the first address returned */
430 *Address = DN2H(IpAddress->Addr);
433 ExFreePool(IpAddress);
435 Status = STATUS_UNSUCCESSFUL;
441 ExFreePool(Entities);
443 TDI_DbgPrint(MAX_TRACE, ("Leaving\n"));
449 NTSTATUS TdiSendDatagram(
450 PFILE_OBJECT TransportObject,
456 * FUNCTION: Sends a datagram
458 * TransportObject = Pointer to transport object
460 * Address = Remote address
461 * Buffer = Pointer to buffer with data to send
462 * BufferSize = Length of Buffer
464 * Status of operation
469 PDEVICE_OBJECT DeviceObject;
470 PTDI_CONNECTION_INFORMATION ConnectInfo;
472 PTDI_ADDRESS_IP IpAddress;
473 IO_STATUS_BLOCK Iosb;
476 DeviceObject = IoGetRelatedDeviceObject(TransportObject);
477 ConnectInfo = (PTDI_CONNECTION_INFORMATION)
478 ExAllocatePool(NonPagedPool,
479 sizeof(TDI_CONNECTION_INFORMATION) +
480 sizeof(TA_ADDRESS_IP));
483 return STATUS_INSUFFICIENT_RESOURCES;
485 RtlZeroMemory(ConnectInfo,
486 sizeof(TDI_CONNECTION_INFORMATION) +
487 sizeof(TA_ADDRESS_IP));
489 ConnectInfo->RemoteAddressLength = sizeof(TA_ADDRESS_IP);
490 ConnectInfo->RemoteAddress = (PUCHAR)
491 ((ULONG)ConnectInfo + sizeof(TDI_CONNECTION_INFORMATION));
493 TA = (PTA_ADDRESS_IP)(ConnectInfo->RemoteAddress);
494 TA->TAAddressCount = 1;
495 TA->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
496 TA->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
497 IpAddress = (PTDI_ADDRESS_IP)(TA->Address[0].Address);
498 IpAddress->sin_port = WH2N(Port);
499 IpAddress->in_addr = DH2N(Address);
500 Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, /* Sub function */
501 DeviceObject, /* Device object */
502 TransportObject, /* File object */
504 NULL); /* Return buffer */
506 TDI_DbgPrint(MIN_TRACE, ("TdiBuildInternalDeviceControlIrp() failed.\n"));
507 ExFreePool(ConnectInfo);
508 return STATUS_INSUFFICIENT_RESOURCES;
511 Mdl = IoAllocateMdl(Buffer, /* Virtual address of buffer */
512 BufferSize, /* Length of buffer */
513 FALSE, /* Not secondary */
514 FALSE, /* Don't charge quota */
515 NULL); /* Don't use IRP */
517 TDI_DbgPrint(MIN_TRACE, ("IoAllocateMdl() failed.\n"));
519 ExFreePool(ConnectInfo);
520 return STATUS_INSUFFICIENT_RESOURCES;
526 MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
528 } except(EXCEPTION_EXECUTE_HANDLER) {
529 TDI_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
532 ExFreePool(ConnectInfo);
533 return STATUS_UNSUCCESSFUL;
537 TdiBuildSendDatagram(Irp, /* I/O Request Packet */
538 DeviceObject, /* Device object */
539 TransportObject, /* File object */
540 NULL, /* Completion routine */
541 NULL, /* Completion context */
542 Mdl, /* Descriptor for data buffer */
543 BufferSize, /* Size of data to send */
544 ConnectInfo); /* Connection information */
546 Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);
548 ExFreePool(ConnectInfo);
554 NTSTATUS TdiReceiveDatagram(
555 PFILE_OBJECT TransportObject,
561 * FUNCTION: Receives a datagram
563 * TransportObject = Pointer to transport object
564 * Port = Port to receive on
565 * Address = Address of buffer to place remote address
566 * Buffer = Address of buffer to place received data
567 * BufferSize = Address of buffer with length of Buffer (updated)
569 * Status of operation
572 PTDI_CONNECTION_INFORMATION ReceiveInfo;
573 PTDI_CONNECTION_INFORMATION ReturnInfo;
574 PTA_ADDRESS_IP ReturnAddress;
575 PDEVICE_OBJECT DeviceObject;
576 PTDI_ADDRESS_IP IpAddress;
577 IO_STATUS_BLOCK Iosb;
583 DeviceObject = IoGetRelatedDeviceObject(TransportObject);
585 return STATUS_INVALID_PARAMETER;
587 ReceiveInfo = (PTDI_CONNECTION_INFORMATION)
588 ExAllocatePool(NonPagedPool,
589 sizeof(TDI_CONNECTION_INFORMATION) +
590 sizeof(TDI_CONNECTION_INFORMATION) +
591 sizeof(TA_ADDRESS_IP));
593 return STATUS_INSUFFICIENT_RESOURCES;
595 MdlBuffer = ExAllocatePool(PagedPool, *BufferSize);
597 return STATUS_INSUFFICIENT_RESOURCES;
600 RtlZeroMemory(ReceiveInfo,
601 sizeof(TDI_CONNECTION_INFORMATION) +
602 sizeof(TDI_CONNECTION_INFORMATION) +
603 sizeof(TA_ADDRESS_IP));
604 RtlCopyMemory(MdlBuffer, Buffer, *BufferSize);
606 /* Receive from any address */
607 ReceiveInfo->RemoteAddressLength = 0;
608 ReceiveInfo->RemoteAddress = NULL;
610 ReturnInfo = (PTDI_CONNECTION_INFORMATION)
611 ((ULONG)ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION));
613 ReturnInfo->RemoteAddressLength = sizeof(TA_ADDRESS_IP);
614 ReturnInfo->RemoteAddress = (PUCHAR)
615 ((ULONG)ReturnInfo + sizeof(TDI_CONNECTION_INFORMATION));
617 ReturnAddress = (PTA_ADDRESS_IP)(ReturnInfo->RemoteAddress);
618 ReturnAddress->TAAddressCount = 1;
619 ReturnAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
620 ReturnAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
622 IpAddress = (PTDI_ADDRESS_IP)(ReturnAddress->Address[0].Address);
623 IpAddress->sin_port = WH2N(Port);
624 IpAddress->in_addr = DH2N(LocalAddress);
626 Irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, /* Sub function */
627 DeviceObject, /* Device object */
628 TransportObject, /* File object */
630 NULL); /* Return buffer */
632 ExFreePool(MdlBuffer);
633 ExFreePool(ReceiveInfo);
634 return STATUS_INSUFFICIENT_RESOURCES;
637 Mdl = IoAllocateMdl(MdlBuffer, /* Virtual address */
638 *BufferSize, /* Length of buffer */
639 FALSE, /* Not secondary */
640 FALSE, /* Don't charge quota */
641 NULL); /* Don't use IRP */
644 ExFreePool(MdlBuffer);
645 ExFreePool(ReceiveInfo);
646 return STATUS_INSUFFICIENT_RESOURCES;
652 MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
654 } except (EXCEPTION_EXECUTE_HANDLER) {
655 TDI_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
658 ExFreePool(MdlBuffer);
659 ExFreePool(ReceiveInfo);
660 return STATUS_INSUFFICIENT_RESOURCES;
664 TdiBuildReceiveDatagram(Irp, /* I/O Request Packet */
665 DeviceObject, /* Device object */
666 TransportObject, /* File object */
667 NULL, /* Completion routine */
668 NULL, /* Completion context */
669 Mdl, /* Data buffer */
670 *BufferSize, /* Size of data buffer */
671 ReceiveInfo, /* Connection information */
672 ReturnInfo, /* Connection information */
673 TDI_RECEIVE_NORMAL); /* Flags */
674 Status = TdiCall(Irp, DeviceObject, &Iosb, TRUE);
675 if (NT_SUCCESS(Status)) {
676 RtlCopyMemory(Buffer, MdlBuffer, Iosb.Information);
677 *BufferSize = Iosb.Information;
678 *Address = DN2H(IpAddress->in_addr);
681 ExFreePool(MdlBuffer);
682 ExFreePool(ReceiveInfo);
691 * FUNCTION: Send thread
693 * Context = Pointer to context information
695 * Transmits an UDP packet every two seconds to ourselves on the chosen port
700 LARGE_INTEGER Timeout;
701 NTSTATUS Status = STATUS_SUCCESS;
702 UCHAR Data[40] = "Testing one, two, three, ...";
705 Timeout.QuadPart = 10000000L; /* Second factor */
706 Timeout.QuadPart *= 2; /* Number of seconds */
707 Timeout.QuadPart = -(Timeout.QuadPart); /* Relative time */
708 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
710 Events[0] = &StopEvent;
713 while (NT_SUCCESS(Status)) {
714 /* Wait until timeout or stop flag is set */
715 KeWaitForMultipleObjects(
725 if (KeReadStateEvent(&StopEvent) != 0) {
726 TDI_DbgPrint(MAX_TRACE, ("Received terminate signal...\n"));
730 DbgPrint("Sending data - '%s'\n", Data);
732 Status = TdiSendDatagram(TdiTransportObject,
737 if (!NT_SUCCESS(Status))
738 DbgPrint("Failed sending data (Status = 0x%X)\n", Status);
742 TDI_DbgPrint(MAX_TRACE, ("Terminating send thread...\n"));
744 KeSetEvent(&SendThreadEvent, 0, FALSE);
746 PsTerminateSystemThread(STATUS_SUCCESS);
750 VOID TdiReceiveThread(
753 * FUNCTION: Receive thread
755 * Context = Pointer to context information
757 * Waits until an UDP packet is received on the chosen endpoint and displays the data
763 NTSTATUS Status = STATUS_SUCCESS;
766 while (NT_SUCCESS(Status)) {
768 RtlZeroMemory(Data, Size);
770 Status = TdiReceiveDatagram(TdiTransportObject,
775 if (NT_SUCCESS(Status)) {
776 DbgPrint("Received data - '%s'\n", Data);
778 if (Status != STATUS_CANCELLED) {
779 TDI_DbgPrint(MIN_TRACE, ("Receive error (Status = 0x%X).\n", Status));
781 TDI_DbgPrint(MAX_TRACE, ("IRP was cancelled.\n"));
786 TDI_DbgPrint(MAX_TRACE, ("Terminating receive thread...\n"));
788 KeSetEvent(&ReceiveThreadEvent, 0, FALSE);
790 PsTerminateSystemThread(STATUS_SUCCESS);
797 * FUNCTION: Open thread
799 * Context = Pointer to context information (event)
804 TDI_DbgPrint(MAX_TRACE, ("Called.\n"));
808 Status = TdiOpenTransport(UDP_DEVICE_NAME,
811 &TdiTransportObject);
812 if (NT_SUCCESS(Status)) {
813 Status = TdiQueryAddress(TdiTransportObject, &LocalAddress);
814 if (NT_SUCCESS(Status)) {
816 DbgPrint("Using local IP address 0x%X\n", LocalAddress);
818 TDI_DbgPrint(MIN_TRACE, ("Unable to determine local IP address.\n"));
821 TDI_DbgPrint(MIN_TRACE, ("Cannot open transport (Status = 0x%X).\n", Status));
823 TDI_DbgPrint(MAX_TRACE, ("Setting close event.\n"));
825 KeSetEvent((PKEVENT)Context, 0, FALSE);
827 TDI_DbgPrint(MIN_TRACE, ("Leaving.\n"));
832 PDRIVER_OBJECT DriverObject)
834 * FUNCTION: Unload routine
836 * DriverObject = Pointer to a driver object for this driver
839 TDI_DbgPrint(MAX_TRACE, ("Setting stop flag\n"));
841 KeSetEvent(&StopEvent, 0, FALSE);
843 /* Wait for send thread to stop */
844 KeWaitForSingleObject(&SendThreadEvent,
850 ObDereferenceObject(SendThreadObject);
852 /* Wait for receive thread to stop */
853 KeWaitForSingleObject(&ReceiveThreadEvent,
859 ObDereferenceObject(ReceiveThreadObject);
862 TdiCloseDevice(TdiTransport, TdiTransportObject);
871 PDRIVER_OBJECT DriverObject,
872 PUNICODE_STRING RegistryPath)
874 * FUNCTION: Main driver entry point
876 * DriverObject = Pointer to a driver object for this driver
877 * RegistryPath = Registry node for configuration parameters
879 * Status of driver initialization
884 WORK_QUEUE_ITEM WorkItem;
886 KeInitializeEvent(&StopEvent, NotificationEvent, FALSE);
887 KeInitializeEvent(&SendThreadEvent, NotificationEvent, FALSE);
888 KeInitializeEvent(&ReceiveThreadEvent, NotificationEvent, FALSE);
890 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
891 ExInitializeWorkItem(&WorkItem, TdiOpenThread, &Event);
892 ExQueueWorkItem(&WorkItem, DelayedWorkQueue);
894 KeWaitForSingleObject(&Event,
901 Status = PsCreateSystemThread(&SendThread, /* Thread handle */
902 0, /* Desired access */
903 NULL, /* Object attributes */
904 NULL, /* Process handle */
905 NULL, /* Client id */
906 (PKSTART_ROUTINE)TdiSendThread, /* Start routine */
907 NULL); /* Start context */
908 if (!NT_SUCCESS(Status)) {
909 TDI_DbgPrint(MIN_TRACE, ("PsCreateSystemThread() failed for send thread (Status = 0x%X).\n", Status));
910 return STATUS_INSUFFICIENT_RESOURCES;
913 /* Get a pointer to the thread object */
914 ObReferenceObjectByHandle(SendThread,
922 Status = PsCreateSystemThread(&ReceiveThread, /* Thread handle */
923 0, /* Desired access */
924 NULL, /* Object attributes */
925 NULL, /* Process handle */
926 NULL, /* Client id */
927 (PKSTART_ROUTINE)TdiReceiveThread, /* Start routine */
928 NULL); /* Start context */
929 if (!NT_SUCCESS(Status)) {
930 TDI_DbgPrint(MIN_TRACE, ("PsCreateSystemThread() failed for receive thread (Status = 0x%X).\n", Status));
932 return STATUS_INSUFFICIENT_RESOURCES;
935 /* Get a pointer to the thread object */
936 ObReferenceObjectByHandle(ReceiveThread,
940 &ReceiveThreadObject,
943 /* Don't need these for anything, so we might as well close them now.
944 The threads will call PsTerminateSystemThread themselves when they are done */
946 ZwClose(ReceiveThread);
948 DriverObject->DriverUnload = (PDRIVER_UNLOAD)TdiUnload;
950 return STATUS_SUCCESS;