485fa702eabc52e5d6a66bc564173a053d59e152
[reactos.git] / rosapps / applications / net / tditest / tditest / tditest.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TDI test driver
4 * FILE: tditest.c
5 * PURPOSE: Testing TDI drivers
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * 26-Nov-2003 Vizzini Updated to run properly on Win2ksp4
11 */
12 #include <tditest.h>
13
14
15 #if DBG
16
17 /* See debug.h for debug/trace constants */
18 ULONG DebugTraceLevel = -1;
19
20 #endif /* DBG */
21
22
23 HANDLE TdiTransport = 0;
24 PFILE_OBJECT TdiTransportObject = NULL;
25 ULONG LocalAddress;
26 BOOLEAN OpenError;
27 KEVENT StopEvent;
28 HANDLE SendThread;
29 HANDLE ReceiveThread;
30
31 NTSTATUS TdiCall(
32 PIRP Irp,
33 PDEVICE_OBJECT DeviceObject,
34 PIO_STATUS_BLOCK IoStatusBlock,
35 BOOLEAN CanCancel)
36 /*
37 * FUNCTION: Calls a transport driver device
38 * ARGUMENTS:
39 * Irp = Pointer to I/O Request Packet
40 * DeviceObject = Pointer to device object to call
41 * IoStatusBlock = Address of buffer with I/O status block
42 * CanCancel = TRUE if the IRP can be cancelled, FALSE if not
43 * RETURNS:
44 * Status of operation
45 * NOTES
46 * All requests are completed synchronously. A request may be cancelled
47 */
48 {
49 KEVENT Event;
50 PKEVENT Events[2];
51 NTSTATUS Status;
52 Events[0] = &StopEvent;
53 Events[1] = &Event;
54
55 KeInitializeEvent(&Event, NotificationEvent, FALSE);
56 Irp->UserEvent = &Event;
57 Irp->UserIosb = IoStatusBlock;
58
59 Status = IoCallDriver(DeviceObject, Irp);
60
61 if (Status == STATUS_PENDING)
62 {
63 if (CanCancel)
64 {
65 Status = KeWaitForMultipleObjects(2, (PVOID)Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
66
67 if (KeReadStateEvent(&StopEvent) != 0)
68 {
69 if (IoCancelIrp(Irp))
70 {
71 TDI_DbgPrint(MAX_TRACE, ("Cancelled IRP.\n"));
72 }
73 else
74 {
75 TDI_DbgPrint(MIN_TRACE, ("Could not cancel IRP.\n"));
76 }
77 return STATUS_CANCELLED;
78 }
79 }
80 else
81 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
82 }
83
84 return (Status == STATUS_SUCCESS)? IoStatusBlock->Status : STATUS_SUCCESS;
85 }
86
87
88 NTSTATUS TdiOpenDevice(
89 PWSTR Protocol,
90 ULONG EaLength,
91 PFILE_FULL_EA_INFORMATION EaInfo,
92 PHANDLE Handle,
93 PFILE_OBJECT *Object)
94 /*
95 * FUNCTION: Opens a device
96 * ARGUMENTS:
97 * Protocol = Pointer to buffer with name of device
98 * EaLength = Length of EA information
99 * EaInfo = Pointer to buffer with EA information
100 * Handle = Address of buffer to place device handle
101 * Object = Address of buffer to place device object
102 * RETURNS:
103 * Status of operation
104 */
105 {
106 OBJECT_ATTRIBUTES Attr;
107 IO_STATUS_BLOCK Iosb;
108 UNICODE_STRING Name;
109 NTSTATUS Status;
110
111 RtlInitUnicodeString(&Name, Protocol);
112 InitializeObjectAttributes(
113 &Attr, /* Attribute buffer */
114 &Name, /* Device name */
115 OBJ_CASE_INSENSITIVE, /* Attributes */
116 NULL, /* Root directory */
117 NULL); /* Security descriptor */
118
119 Status = ZwCreateFile(
120 Handle, /* Return file handle */
121 GENERIC_READ | GENERIC_WRITE, /* Desired access */
122 &Attr, /* Object attributes */
123 &Iosb, /* IO status */
124 0, /* Initial allocation size */
125 FILE_ATTRIBUTE_NORMAL, /* File attributes */
126 FILE_SHARE_READ | FILE_SHARE_WRITE, /* Share access */
127 FILE_OPEN_IF, /* Create disposition */
128 0, /* Create options */
129 EaInfo, /* EA buffer */
130 EaLength); /* EA length */
131
132 if (NT_SUCCESS(Status))
133 {
134 Status = ObReferenceObjectByHandle(
135 *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
142 if (!NT_SUCCESS(Status))
143 {
144 TDI_DbgPrint(MIN_TRACE, ("ObReferenceObjectByHandle() failed with status (0x%X).\n", Status));
145 ZwClose(*Handle);
146 }
147 }
148 else
149 {
150 TDI_DbgPrint(MIN_TRACE, ("ZwCreateFile() failed with status (0x%X)\n", Status));
151 }
152
153 return Status;
154 }
155
156
157 NTSTATUS TdiCloseDevice(
158 HANDLE Handle,
159 PFILE_OBJECT FileObject)
160 {
161 if (FileObject)
162 ObDereferenceObject(FileObject);
163
164 if (Handle)
165 ZwClose(Handle);
166
167 return STATUS_SUCCESS;
168 }
169
170
171 NTSTATUS TdiOpenTransport(
172 PWSTR Protocol,
173 USHORT Port,
174 PHANDLE Transport,
175 PFILE_OBJECT *TransportObject)
176 /*
177 * FUNCTION: Opens a transport driver
178 * ARGUMENTS:
179 * Protocol = Pointer to buffer with name of device
180 * Port = Port number to use
181 * Transport = Address of buffer to place transport device handle
182 * TransportObject = Address of buffer to place transport object
183 * RETURNS:
184 * Status of operation
185 */
186 {
187 PFILE_FULL_EA_INFORMATION EaInfo;
188 PTA_IP_ADDRESS Address;
189 NTSTATUS Status;
190 ULONG EaLength;
191
192 /* EaName must be 0-termed, even though TDI_TRANSPORT_ADDRESS_LENGTH does *not* include the 0 */
193 EaLength = sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_IP_ADDRESS) + 1;
194 EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, EaLength);
195
196 if (!EaInfo)
197 {
198 TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
199 return STATUS_INSUFFICIENT_RESOURCES;
200 }
201
202 RtlZeroMemory(EaInfo, EaLength);
203
204 EaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
205
206 /* don't copy the 0; we have already zeroed it */
207 RtlCopyMemory(EaInfo->EaName, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH);
208
209 EaInfo->EaValueLength = sizeof(TA_IP_ADDRESS);
210 Address = (PTA_IP_ADDRESS)(EaInfo->EaName + TDI_TRANSPORT_ADDRESS_LENGTH + 1); // 0-term
211 Address->TAAddressCount = 1;
212 Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
213 Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
214 Address->Address[0].Address[0].sin_port = WH2N(Port);
215 Address->Address[0].Address[0].in_addr = 0;
216
217 Status = TdiOpenDevice(Protocol, EaLength, EaInfo, Transport, TransportObject);
218
219 ExFreePool(EaInfo);
220
221 return Status;
222 }
223
224
225 NTSTATUS TdiQueryDeviceControl(
226 PFILE_OBJECT FileObject,
227 ULONG IoControlCode,
228 PVOID InputBuffer,
229 ULONG InputBufferLength,
230 PVOID OutputBuffer,
231 ULONG OutputBufferLength,
232 PULONG Return)
233 /*
234 * FUNCTION: Queries a device for information
235 * ARGUMENTS:
236 * FileObject = Pointer to device object
237 * IoControlCode = I/O control code
238 * InputBuffer = Pointer to buffer with input data
239 * InputBufferLength = Length of InputBuffer
240 * OutputBuffer = Address of buffer to place output data
241 * OutputBufferLength = Length of OutputBuffer
242 * RETURNS:
243 * Status of operation
244 */
245 {
246 PDEVICE_OBJECT DeviceObject;
247 PIO_STACK_LOCATION IoStack;
248 IO_STATUS_BLOCK Iosb;
249 NTSTATUS Status;
250 PIRP Irp;
251
252 DeviceObject = IoGetRelatedDeviceObject(FileObject);
253 Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer, InputBufferLength, OutputBuffer,
254 OutputBufferLength, FALSE, NULL, NULL);
255
256 if (!Irp)
257 {
258 TDI_DbgPrint(MIN_TRACE, ("IoBuildDeviceIoControlRequest() failed.\n"));
259 return STATUS_INSUFFICIENT_RESOURCES;
260 }
261
262 IoStack = IoGetNextIrpStackLocation(Irp);
263 IoStack->DeviceObject = DeviceObject;
264 IoStack->FileObject = FileObject;
265 Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);
266
267 if (Return)
268 *Return = Iosb.Information;
269
270 return Status;
271 }
272
273
274 NTSTATUS TdiQueryInformationEx(
275 PFILE_OBJECT FileObject,
276 ULONG Entity,
277 ULONG Instance,
278 ULONG Class,
279 ULONG Type,
280 ULONG Id,
281 PVOID OutputBuffer,
282 PULONG OutputLength)
283 /*
284 * FUNCTION: Extended query for information
285 * ARGUMENTS:
286 * FileObject = Pointer to transport object
287 * Entity = Entity
288 * Instance = Instance
289 * Class = Entity class
290 * Type = Entity type
291 * Id = Entity id
292 * OutputBuffer = Address of buffer to place data
293 * OutputLength = Address of buffer with length of OutputBuffer (updated)
294 * RETURNS:
295 * Status of operation
296 */
297 {
298 TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;
299
300 RtlZeroMemory(&QueryInfo, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
301 QueryInfo.ID.toi_entity.tei_entity = Entity;
302 QueryInfo.ID.toi_entity.tei_instance = Instance;
303 QueryInfo.ID.toi_class = Class;
304 QueryInfo.ID.toi_type = Type;
305 QueryInfo.ID.toi_id = Id;
306
307 return TdiQueryDeviceControl(
308 FileObject, /* Transport/connection object */
309 IOCTL_TCP_QUERY_INFORMATION_EX, /* Control code */
310 &QueryInfo, /* Input buffer */
311 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), /* Input buffer length */
312 OutputBuffer, /* Output buffer */
313 *OutputLength, /* Output buffer length */
314 OutputLength); /* Return information */
315 }
316
317
318 NTSTATUS TdiQueryAddress(
319 PFILE_OBJECT FileObject,
320 PULONG Address)
321 /*
322 * FUNCTION: Queries for a local IP address
323 * ARGUMENTS:
324 * FileObject = Pointer to file object
325 * Address = Address of buffer to place local address
326 * RETURNS:
327 * Status of operation
328 */
329 {
330 ULONG i;
331 TDIEntityID *Entities;
332 ULONG EntityCount;
333 ULONG EntityType;
334 IPSNMP_INFO SnmpInfo;
335 PIPADDR_ENTRY IpAddress;
336 ULONG BufferSize;
337 NTSTATUS Status = STATUS_SUCCESS;
338
339 TDI_DbgPrint(MAX_TRACE, ("Called\n"));
340
341 BufferSize = sizeof(TDIEntityID) * 20;
342 Entities = (TDIEntityID*)ExAllocatePool(NonPagedPool, BufferSize);
343
344 if (!Entities)
345 {
346 TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
347 return STATUS_INSUFFICIENT_RESOURCES;
348 }
349
350 /* Query device for supported entities */
351 Status = TdiQueryInformationEx(
352 FileObject, /* File object */
353 GENERIC_ENTITY, /* Entity */
354 TL_INSTANCE, /* Instance */
355 INFO_CLASS_GENERIC, /* Entity class */
356 INFO_TYPE_PROVIDER, /* Entity type */
357 ENTITY_LIST_ID, /* Entity id */
358 Entities, /* Output buffer */
359 &BufferSize); /* Output buffer size */
360
361 if (!NT_SUCCESS(Status))
362 {
363 TDI_DbgPrint(MIN_TRACE, ("Unable to get list of supported entities (Status = 0x%X).\n", Status));
364 ExFreePool(Entities);
365 return Status;
366 }
367
368 /* Locate an IP entity */
369 EntityCount = BufferSize / sizeof(TDIEntityID);
370
371 TDI_DbgPrint(MAX_TRACE, ("EntityCount = %d\n", EntityCount));
372
373 for (i = 0; i < EntityCount; i++)
374 {
375 if (Entities[i].tei_entity == CL_NL_ENTITY)
376 {
377 /* Query device for entity type */
378 BufferSize = sizeof(EntityType);
379 Status = TdiQueryInformationEx(
380 FileObject, /* File object */
381 CL_NL_ENTITY, /* Entity */
382 Entities[i].tei_instance, /* Instance */
383 INFO_CLASS_GENERIC, /* Entity class */
384 INFO_TYPE_PROVIDER, /* Entity type */
385 ENTITY_TYPE_ID, /* Entity id */
386 &EntityType, /* Output buffer */
387 &BufferSize); /* Output buffer size */
388
389 if (!NT_SUCCESS(Status) || (EntityType != CL_NL_IP))
390 {
391 TDI_DbgPrint(MIN_TRACE, ("Unable to get entity of type IP (Status = 0x%X).\n", Status));
392 break;
393 }
394
395 /* Query device for SNMP information */
396 BufferSize = sizeof(SnmpInfo);
397 Status = TdiQueryInformationEx(
398 FileObject, /* File object */
399 CL_NL_ENTITY, /* Entity */
400 Entities[i].tei_instance, /* Instance */
401 INFO_CLASS_PROTOCOL, /* Entity class */
402 INFO_TYPE_PROVIDER, /* Entity type */
403 IP_MIB_STATS_ID, /* Entity id */
404 &SnmpInfo, /* Output buffer */
405 &BufferSize); /* Output buffer size */
406
407 if (!NT_SUCCESS(Status) || (SnmpInfo.NumAddr == 0))
408 {
409 TDI_DbgPrint(MIN_TRACE, ("Unable to get SNMP information or no IP addresses available (Status = 0x%X).\n", Status));
410 break;
411 }
412
413 /* Query device for all IP addresses */
414 if (SnmpInfo.NumAddr != 0)
415 {
416 BufferSize = SnmpInfo.NumAddr * sizeof(IPADDR_ENTRY);
417 IpAddress = (PIPADDR_ENTRY)ExAllocatePool(NonPagedPool, BufferSize);
418 if (!IpAddress)
419 {
420 TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
421 break;
422 }
423
424 Status = TdiQueryInformationEx(
425 FileObject, /* File object */
426 CL_NL_ENTITY, /* Entity */
427 Entities[i].tei_instance, /* Instance */
428 INFO_CLASS_PROTOCOL, /* Entity class */
429 INFO_TYPE_PROVIDER, /* Entity type */
430 IP_MIB_ADDRTABLE_ENTRY_ID, /* Entity id */
431 IpAddress, /* Output buffer */
432 &BufferSize); /* Output buffer size */
433
434 if (!NT_SUCCESS(Status))
435 {
436 TDI_DbgPrint(MIN_TRACE, ("Unable to get IP address (Status = 0x%X).\n", Status));
437 ExFreePool(IpAddress);
438 break;
439 }
440
441 if (SnmpInfo.NumAddr != 1)
442 {
443 /* Skip loopback address */
444 *Address = DN2H(((PIPADDR_ENTRY)((ULONG)IpAddress + sizeof(IPADDR_ENTRY)))->Addr);
445 }
446 else
447 {
448 /* Select the first address returned */
449 *Address = DN2H(IpAddress->Addr);
450 }
451 ExFreePool(IpAddress);
452
453 }
454 else
455 {
456 Status = STATUS_UNSUCCESSFUL;
457 break;
458 }
459 }
460 }
461
462 ExFreePool(Entities);
463
464 TDI_DbgPrint(MAX_TRACE, ("Leaving\n"));
465
466 return Status;
467 }
468
469
470 NTSTATUS TdiSendDatagram(
471 PFILE_OBJECT TransportObject,
472 USHORT Port,
473 ULONG Address,
474 PVOID Buffer,
475 ULONG BufferSize)
476 /*
477 * FUNCTION: Sends a datagram
478 * ARGUMENTS:
479 * TransportObject = Pointer to transport object
480 * Port = Remote port
481 * Address = Remote address
482 * Buffer = Pointer to buffer with data to send
483 * BufferSize = Length of Buffer
484 * RETURNS:
485 * Status of operation
486 */
487 {
488 PIRP Irp;
489 PMDL Mdl;
490 PDEVICE_OBJECT DeviceObject;
491 PTDI_CONNECTION_INFORMATION ConnectInfo;
492 PTA_IP_ADDRESS TA;
493 PTDI_ADDRESS_IP IpAddress;
494 IO_STATUS_BLOCK Iosb;
495 NTSTATUS Status;
496
497 DeviceObject = IoGetRelatedDeviceObject(TransportObject);
498 ConnectInfo = (PTDI_CONNECTION_INFORMATION)
499 ExAllocatePool(NonPagedPool,
500 sizeof(TDI_CONNECTION_INFORMATION) +
501 sizeof(TA_IP_ADDRESS));
502
503 if (!ConnectInfo)
504 return STATUS_INSUFFICIENT_RESOURCES;
505
506 RtlZeroMemory(ConnectInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
507
508 ConnectInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
509 ConnectInfo->RemoteAddress = (PUCHAR) ((ULONG)ConnectInfo + sizeof(TDI_CONNECTION_INFORMATION));
510
511 TA = (PTA_IP_ADDRESS)(ConnectInfo->RemoteAddress);
512 TA->TAAddressCount = 1;
513 TA->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
514 TA->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
515 IpAddress = (PTDI_ADDRESS_IP)(TA->Address[0].Address);
516 IpAddress->sin_port = WH2N(Port);
517 IpAddress->in_addr = DH2N(Address);
518 Irp = TdiBuildInternalDeviceControlIrp(
519 TDI_SEND_DATAGRAM, /* Sub function */
520 DeviceObject, /* Device object */
521 TransportObject, /* File object */
522 NULL, /* Event */
523 NULL); /* Return buffer */
524
525 if (!Irp)
526 {
527 TDI_DbgPrint(MIN_TRACE, ("TdiBuildInternalDeviceControlIrp() failed.\n"));
528 ExFreePool(ConnectInfo);
529 return STATUS_INSUFFICIENT_RESOURCES;
530 }
531
532 Mdl = IoAllocateMdl(
533 Buffer, /* Virtual address of buffer */
534 BufferSize, /* Length of buffer */
535 FALSE, /* Not secondary */
536 FALSE, /* Don't charge quota */
537 NULL); /* Don't use IRP */
538
539 if (!Mdl)
540 {
541 TDI_DbgPrint(MIN_TRACE, ("IoAllocateMdl() failed.\n"));
542 IoFreeIrp(Irp);
543 ExFreePool(ConnectInfo);
544 return STATUS_INSUFFICIENT_RESOURCES;
545 }
546
547 #ifdef _MSC_VER
548 try
549 {
550 #endif
551 MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
552 #ifdef _MSC_VER
553 }
554 except(EXCEPTION_EXECUTE_HANDLER)
555 {
556 TDI_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
557 IoFreeMdl(Mdl);
558 IoFreeIrp(Irp);
559 ExFreePool(ConnectInfo);
560 return STATUS_UNSUCCESSFUL;
561 }
562 #endif
563
564 TdiBuildSendDatagram(
565 Irp, /* I/O Request Packet */
566 DeviceObject, /* Device object */
567 TransportObject, /* File object */
568 NULL, /* Completion routine */
569 NULL, /* Completion context */
570 Mdl, /* Descriptor for data buffer */
571 BufferSize, /* Size of data to send */
572 ConnectInfo); /* Connection information */
573
574 Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);
575
576 ExFreePool(ConnectInfo);
577
578 return Status;
579 }
580
581
582 NTSTATUS TdiReceiveDatagram(
583 PFILE_OBJECT TransportObject,
584 USHORT Port,
585 PULONG Address,
586 PUCHAR Buffer,
587 PULONG BufferSize)
588 /*
589 * FUNCTION: Receives a datagram
590 * ARGUMENTS:
591 * TransportObject = Pointer to transport object
592 * Port = Port to receive on
593 * Address = Address of buffer to place remote address
594 * Buffer = Address of buffer to place received data
595 * BufferSize = Address of buffer with length of Buffer (updated)
596 * RETURNS:
597 * Status of operation
598 */
599 {
600 PTDI_CONNECTION_INFORMATION ReceiveInfo;
601 PTDI_CONNECTION_INFORMATION ReturnInfo;
602 PTA_IP_ADDRESS ReturnAddress;
603 PDEVICE_OBJECT DeviceObject;
604 PTDI_ADDRESS_IP IpAddress;
605 IO_STATUS_BLOCK Iosb;
606 PVOID MdlBuffer;
607 NTSTATUS Status;
608 PIRP Irp;
609 PMDL Mdl;
610
611 DeviceObject = IoGetRelatedDeviceObject(TransportObject);
612 if (!DeviceObject)
613 return STATUS_INVALID_PARAMETER;
614
615 ReceiveInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool,
616 sizeof(TDI_CONNECTION_INFORMATION) +
617 sizeof(TDI_CONNECTION_INFORMATION) +
618 sizeof(TA_IP_ADDRESS));
619
620 if (!ReceiveInfo)
621 return STATUS_INSUFFICIENT_RESOURCES;
622
623 MdlBuffer = ExAllocatePool(PagedPool, *BufferSize);
624 if (!MdlBuffer)
625 return STATUS_INSUFFICIENT_RESOURCES;
626
627 RtlZeroMemory(ReceiveInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TDI_CONNECTION_INFORMATION) +
628 sizeof(TA_IP_ADDRESS));
629
630 RtlCopyMemory(MdlBuffer, Buffer, *BufferSize);
631
632 /* Receive from any address */
633 ReceiveInfo->RemoteAddressLength = 0;
634 ReceiveInfo->RemoteAddress = NULL;
635
636 ReturnInfo = (PTDI_CONNECTION_INFORMATION) ((ULONG)ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION));
637 ReturnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
638 ReturnInfo->RemoteAddress = (PUCHAR) ((ULONG)ReturnInfo + sizeof(TDI_CONNECTION_INFORMATION));
639
640 ReturnAddress = (PTA_IP_ADDRESS)(ReturnInfo->RemoteAddress);
641 ReturnAddress->TAAddressCount = 1;
642 ReturnAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
643 ReturnAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
644
645 IpAddress = (PTDI_ADDRESS_IP)(ReturnAddress->Address[0].Address);
646 IpAddress->sin_port = WH2N(Port);
647 IpAddress->in_addr = DH2N(LocalAddress);
648
649 Irp = TdiBuildInternalDeviceControlIrp(
650 TDI_RECEIVE_DATAGRAM, /* Sub function */
651 DeviceObject, /* Device object */
652 TransportObject, /* File object */
653 NULL, /* Event */
654 NULL); /* Return buffer */
655
656 if (!Irp)
657 {
658 ExFreePool(MdlBuffer);
659 ExFreePool(ReceiveInfo);
660 return STATUS_INSUFFICIENT_RESOURCES;
661 }
662
663 Mdl = IoAllocateMdl(
664 MdlBuffer, /* Virtual address */
665 *BufferSize, /* Length of buffer */
666 FALSE, /* Not secondary */
667 FALSE, /* Don't charge quota */
668 NULL); /* Don't use IRP */
669
670 if (!Mdl)
671 {
672 IoFreeIrp(Irp);
673 ExFreePool(MdlBuffer);
674 ExFreePool(ReceiveInfo);
675 return STATUS_INSUFFICIENT_RESOURCES;
676 }
677
678 #ifdef _MSC_VER
679 try
680 {
681 #endif
682 MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
683 #ifdef _MSC_VER
684 }
685 except (EXCEPTION_EXECUTE_HANDLER)
686 {
687 TDI_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
688 IoFreeMdl(Mdl);
689 IoFreeIrp(Irp);
690 ExFreePool(MdlBuffer);
691 ExFreePool(ReceiveInfo);
692 return STATUS_INSUFFICIENT_RESOURCES;
693 }
694 #endif
695
696 TdiBuildReceiveDatagram(
697 Irp, /* I/O Request Packet */
698 DeviceObject, /* Device object */
699 TransportObject, /* File object */
700 NULL, /* Completion routine */
701 NULL, /* Completion context */
702 Mdl, /* Data buffer */
703 *BufferSize, /* Size of data buffer */
704 ReceiveInfo, /* Connection information */
705 ReturnInfo, /* Connection information */
706 TDI_RECEIVE_NORMAL); /* Flags */
707
708 Status = TdiCall(Irp, DeviceObject, &Iosb, TRUE);
709
710 if (NT_SUCCESS(Status))
711 {
712 RtlCopyMemory(Buffer, MdlBuffer, Iosb.Information);
713 *BufferSize = Iosb.Information;
714 *Address = DN2H(IpAddress->in_addr);
715 }
716
717 ExFreePool(MdlBuffer);
718 ExFreePool(ReceiveInfo);
719
720 return Status;
721 }
722
723
724 VOID TdiSendThread(
725 PVOID Context)
726 /*
727 * FUNCTION: Send thread
728 * ARGUMENTS:
729 * Context = Pointer to context information
730 * NOTES:
731 * Transmits an UDP packet every two seconds to ourselves on the chosen port
732 */
733 {
734 KEVENT Event;
735 PKEVENT Events[2];
736 LARGE_INTEGER Timeout;
737 NTSTATUS Status = STATUS_SUCCESS;
738 UCHAR Data[40] = "Testing one, two, three, ...";
739
740 if (!OpenError)
741 {
742 Timeout.QuadPart = 10000000L; /* Second factor */
743 Timeout.QuadPart *= 2; /* Number of seconds */
744 Timeout.QuadPart = -(Timeout.QuadPart); /* Relative time */
745
746 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
747
748 Events[0] = &StopEvent;
749 Events[1] = &Event;
750
751 while (NT_SUCCESS(Status))
752 {
753 /* Wait until timeout or stop flag is set */
754 KeWaitForMultipleObjects( 2, (PVOID)Events, WaitAny, Executive, KernelMode, FALSE, &Timeout, NULL);
755
756 if (KeReadStateEvent(&StopEvent) != 0)
757 {
758 TDI_DbgPrint(MAX_TRACE, ("Received terminate signal...\n"));
759 break;
760 }
761
762 DbgPrint("Sending data - '%s'\n", Data);
763
764 Status = TdiSendDatagram(TdiTransportObject, TEST_PORT, LocalAddress, Data, sizeof(Data));
765
766 if (!NT_SUCCESS(Status))
767 DbgPrint("Failed sending data (Status = 0x%X)\n", Status);
768 }
769 }
770
771 TDI_DbgPrint(MAX_TRACE, ("Terminating send thread...\n"));
772
773 PsTerminateSystemThread(STATUS_SUCCESS);
774 }
775
776
777 VOID TdiReceiveThread(
778 PVOID Context)
779 /*
780 * FUNCTION: Receive thread
781 * ARGUMENTS:
782 * Context = Pointer to context information
783 * NOTES:
784 * Waits until an UDP packet is received on the chosen endpoint and displays the data
785 */
786 {
787 ULONG Address;
788 UCHAR Data[40];
789 ULONG Size;
790 NTSTATUS Status = STATUS_SUCCESS;
791
792 if (!OpenError)
793 {
794 while (NT_SUCCESS(Status))
795 {
796 Size = sizeof(Data);
797 RtlZeroMemory(Data, Size);
798
799 Status = TdiReceiveDatagram(TdiTransportObject, TEST_PORT, &Address, Data, &Size);
800
801 if (NT_SUCCESS(Status))
802 {
803 DbgPrint("Received data - '%s'\n", Data);
804 }
805 else
806 if (Status != STATUS_CANCELLED)
807 {
808 TDI_DbgPrint(MIN_TRACE, ("Receive error (Status = 0x%X).\n", Status));
809 }
810 else
811 {
812 TDI_DbgPrint(MAX_TRACE, ("IRP was cancelled.\n"));
813 }
814 }
815 }
816
817 TDI_DbgPrint(MAX_TRACE, ("Terminating receive thread...\n"));
818
819 PsTerminateSystemThread(STATUS_SUCCESS);
820 }
821
822
823 VOID TdiOpenThread(
824 PVOID Context)
825 /*
826 * FUNCTION: Open thread
827 * ARGUMENTS:
828 * Context = Pointer to context information (event)
829 */
830 {
831 NTSTATUS Status;
832
833 TDI_DbgPrint(MAX_TRACE, ("Called.\n"));
834
835 OpenError = TRUE;
836
837 Status = TdiOpenTransport(UDP_DEVICE_NAME, TEST_PORT, &TdiTransport, &TdiTransportObject);
838
839 if (NT_SUCCESS(Status))
840 {
841 Status = TdiQueryAddress(TdiTransportObject, &LocalAddress);
842
843 if (NT_SUCCESS(Status))
844 {
845 OpenError = FALSE;
846 DbgPrint("Using local IP address 0x%X\n", LocalAddress);
847 }
848 else
849 {
850 TDI_DbgPrint(MIN_TRACE, ("Unable to determine local IP address.\n"));
851 }
852 }
853 else
854 TDI_DbgPrint(MIN_TRACE, ("Cannot open transport (Status = 0x%X).\n", Status));
855
856 TDI_DbgPrint(MAX_TRACE, ("Setting close event.\n"));
857
858 KeSetEvent((PKEVENT)Context, 0, FALSE);
859
860 TDI_DbgPrint(MIN_TRACE, ("Leaving.\n"));
861 }
862
863
864 VOID TdiUnload(
865 PDRIVER_OBJECT DriverObject)
866 /*
867 * FUNCTION: Unload routine
868 * ARGUMENTS:
869 * DriverObject = Pointer to a driver object for this driver
870 */
871 {
872 PVOID ReceiveThreadObject = 0;
873 PVOID SendThreadObject = 0;
874
875 TDI_DbgPrint(MAX_TRACE, ("Setting stop flag\n"));
876
877 /* Get pointers to the thread objects */
878 ObReferenceObjectByHandle(SendThread, THREAD_ALL_ACCESS, NULL, KernelMode, &SendThreadObject, NULL);
879 ObReferenceObjectByHandle(ReceiveThread, THREAD_ALL_ACCESS, NULL, KernelMode, &ReceiveThreadObject, NULL);
880
881 KeSetEvent(&StopEvent, 0, FALSE);
882
883 /* Wait for send thread to stop */
884 KeWaitForSingleObject(SendThreadObject, Executive, KernelMode, FALSE, NULL);
885
886 /* Wait for receive thread to stop */
887 KeWaitForSingleObject(ReceiveThreadObject, Executive, KernelMode, FALSE, NULL);
888
889 /* Close device */
890 TdiCloseDevice(TdiTransport, TdiTransportObject);
891 }
892
893
894 NTSTATUS
895 NTAPI
896 DriverEntry(
897 PDRIVER_OBJECT DriverObject,
898 PUNICODE_STRING RegistryPath)
899 /*
900 * FUNCTION: Main driver entry point
901 * ARGUMENTS:
902 * DriverObject = Pointer to a driver object for this driver
903 * RegistryPath = Registry node for configuration parameters
904 * RETURNS:
905 * Status of driver initialization
906 */
907 {
908 KEVENT Event;
909 NTSTATUS Status;
910 WORK_QUEUE_ITEM WorkItem;
911
912 KeInitializeEvent(&StopEvent, NotificationEvent, FALSE);
913
914 /* Call TdiOpenThread() */
915 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
916 ExInitializeWorkItem(&WorkItem, (PWORKER_THREAD_ROUTINE)TdiOpenThread, &Event);
917 ExQueueWorkItem(&WorkItem, DelayedWorkQueue);
918 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, NULL);
919
920 /* Create a UDP send thread that sends a dgram every 2 seconds */
921 Status = PsCreateSystemThread(
922 &SendThread, /* Thread handle */
923 0, /* Desired access */
924 NULL, /* Object attributes */
925 NULL, /* Process handle */
926 NULL, /* Client id */
927 (PKSTART_ROUTINE)TdiSendThread, /* Start routine */
928 NULL); /* Start context */
929
930 if (!NT_SUCCESS(Status))
931 {
932 TDI_DbgPrint(MIN_TRACE, ("PsCreateSystemThread() failed for send thread (Status = 0x%X).\n", Status));
933 return STATUS_INSUFFICIENT_RESOURCES;
934 }
935
936 /* Create a UDP receive thread */
937 Status = PsCreateSystemThread(
938 &ReceiveThread, /* Thread handle */
939 0, /* Desired access */
940 NULL, /* Object attributes */
941 NULL, /* Process handle */
942 NULL, /* Client id */
943 (PKSTART_ROUTINE)TdiReceiveThread, /* Start routine */
944 NULL); /* Start context */
945
946 if (!NT_SUCCESS(Status))
947 {
948 TDI_DbgPrint(MIN_TRACE, ("PsCreateSystemThread() failed for receive thread (Status = 0x%X).\n", Status));
949 ZwClose(SendThread);
950 return STATUS_INSUFFICIENT_RESOURCES;
951 }
952
953 DriverObject->DriverUnload = (PDRIVER_UNLOAD)TdiUnload;
954
955 return STATUS_SUCCESS;
956 }
957
958 /* EOF */
959