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)((PUCHAR)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)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 _SEH2_YIELD(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) ((PUCHAR)ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION)); 634 ReturnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS); 635 ReturnInfo->RemoteAddress = ((PUCHAR)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 _SEH2_YIELD(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 953