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