|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1989-1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: connect.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains code which performs the following TDI services: ! 12: ! 13: o TdiAccept ! 14: o TdiListen ! 15: o TdiConnect ! 16: o TdiDisconnect ! 17: o TdiAssociateAddress ! 18: o TdiDisassociateAddress ! 19: o OpenConnection ! 20: o CloseConnection ! 21: ! 22: Environment: ! 23: ! 24: Kernel mode ! 25: ! 26: Revision History: ! 27: ! 28: --*/ ! 29: ! 30: #include "st.h" ! 31: ! 32: ! 33: NTSTATUS ! 34: StTdiAccept( ! 35: IN PIRP Irp ! 36: ) ! 37: ! 38: /*++ ! 39: ! 40: Routine Description: ! 41: ! 42: This routine performs the TdiAccept request for the transport provider. ! 43: ! 44: Arguments: ! 45: ! 46: Irp - Pointer to the I/O Request Packet for this request. ! 47: ! 48: Return Value: ! 49: ! 50: NTSTATUS - status of operation. ! 51: ! 52: --*/ ! 53: ! 54: { ! 55: PTP_CONNECTION connection; ! 56: PIO_STACK_LOCATION irpSp; ! 57: KIRQL oldirql; ! 58: NTSTATUS status; ! 59: ! 60: // ! 61: // Get the connection this is associated with; if there is none, get out. ! 62: // ! 63: ! 64: irpSp = IoGetCurrentIrpStackLocation (Irp); ! 65: ! 66: connection = irpSp->FileObject->FsContext; ! 67: ! 68: // ! 69: // This adds a connection reference if successful. ! 70: // ! 71: ! 72: status = StVerifyConnectionObject (connection); ! 73: ! 74: if (!NT_SUCCESS (status)) { ! 75: return status; ! 76: } ! 77: ! 78: // ! 79: // just set the connection flags to allow reads and writes to proceed. ! 80: // ! 81: ! 82: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql); ! 83: ! 84: // ! 85: // Turn off the stopping flag for this connection. ! 86: // ! 87: ! 88: connection->Flags &= ~CONNECTION_FLAGS_STOPPING; ! 89: connection->Status = STATUS_PENDING; ! 90: ! 91: connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED; ! 92: ! 93: ! 94: if (connection->AddressFile->ConnectIndicationInProgress) { ! 95: connection->Flags2 |= CONNECTION_FLAGS2_INDICATING; ! 96: } ! 97: ! 98: if ((connection->Flags2 & CONNECTION_FLAGS2_WAIT_ACCEPT) != 0) { ! 99: ! 100: // ! 101: // We previously completed a listen, now the user is ! 102: // coming back with an accept, Set this flag to allow ! 103: // the connection to proceed. ! 104: // ! 105: ! 106: connection->Flags |= CONNECTION_FLAGS_READY; ! 107: ! 108: INCREMENT_COUNTER (connection->Provider, OpenConnections); ! 109: ! 110: // ! 111: // Set this flag to enable disconnect indications; once ! 112: // the client has accepted he expects those. ! 113: // ! 114: ! 115: connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_ACCEPT; ! 116: connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED; ! 117: ! 118: StReferenceConnection("Pended listen completed", connection); ! 119: ! 120: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 121: ! 122: } else { ! 123: ! 124: // ! 125: // This accept is being called at some point before ! 126: // the link is up; directly from the connection handler ! 127: // or at some point slightly later. ! 128: // ! 129: ! 130: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 131: ! 132: } ! 133: ! 134: StDereferenceConnection ("Temp TdiAccept", connection); ! 135: ! 136: return STATUS_SUCCESS; ! 137: ! 138: } /* StTdiAccept */ ! 139: ! 140: ! 141: NTSTATUS ! 142: StTdiAssociateAddress( ! 143: IN PIRP Irp ! 144: ) ! 145: ! 146: /*++ ! 147: ! 148: Routine Description: ! 149: ! 150: This routine performs the association of the connection and the address for ! 151: the user. ! 152: ! 153: Arguments: ! 154: ! 155: Irp - Pointer to the I/O Request Packet for this request. ! 156: ! 157: Return Value: ! 158: ! 159: NTSTATUS - status of operation. ! 160: ! 161: --*/ ! 162: ! 163: { ! 164: NTSTATUS status; ! 165: PFILE_OBJECT fileObject; ! 166: PTP_ADDRESS_FILE addressFile; ! 167: PTP_ADDRESS oldAddress; ! 168: PTP_CONNECTION connection; ! 169: PIO_STACK_LOCATION irpSp; ! 170: PTDI_REQUEST_KERNEL_ASSOCIATE parameters; ! 171: PDEVICE_CONTEXT deviceContext; ! 172: ! 173: KIRQL oldirql, oldirql2; ! 174: ! 175: irpSp = IoGetCurrentIrpStackLocation (Irp); ! 176: ! 177: // ! 178: // verify that the operation is taking place on a connection. At the same ! 179: // time we do this, we reference the connection. This ensures it does not ! 180: // get removed out from under us. Note also that we do the connection ! 181: // lookup within a try/except clause, thus protecting ourselves against ! 182: // really bogus handles ! 183: // ! 184: ! 185: connection = irpSp->FileObject->FsContext; ! 186: status = StVerifyConnectionObject (connection); ! 187: if (!NT_SUCCESS (status)) { ! 188: return status; ! 189: } ! 190: ! 191: ! 192: // ! 193: // Make sure this connection is ready to be associated. ! 194: // ! 195: ! 196: oldAddress = (PTP_ADDRESS)NULL; ! 197: ! 198: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2); ! 199: ! 200: if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) && ! 201: ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) { ! 202: ! 203: // ! 204: // The connection is already associated with ! 205: // an active connection...bad! ! 206: // ! 207: ! 208: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2); ! 209: StDereferenceConnection ("Temp Ref Associate", connection); ! 210: ! 211: return STATUS_INVALID_CONNECTION; ! 212: ! 213: } else { ! 214: ! 215: // ! 216: // See if there is an old association hanging around... ! 217: // this happens if the connection has been disassociated, ! 218: // but not closed. ! 219: // ! 220: ! 221: if (connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) { ! 222: ! 223: // ! 224: // Save this; since it is non-null this address ! 225: // will be dereferenced after the connection ! 226: // spinlock is released. ! 227: // ! 228: ! 229: oldAddress = connection->AddressFile->Address; ! 230: ! 231: // ! 232: // Remove the old association. ! 233: // ! 234: ! 235: connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED; ! 236: RemoveEntryList (&connection->AddressList); ! 237: RemoveEntryList (&connection->AddressFileList); ! 238: InitializeListHead (&connection->AddressList); ! 239: InitializeListHead (&connection->AddressFileList); ! 240: connection->AddressFile = NULL; ! 241: ! 242: } ! 243: ! 244: } ! 245: ! 246: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2); ! 247: ! 248: // ! 249: // If we removed an old association, dereference the ! 250: // address. ! 251: // ! 252: ! 253: if (oldAddress != (PTP_ADDRESS)NULL) { ! 254: ! 255: StDereferenceAddress("Removed old association", oldAddress); ! 256: ! 257: } ! 258: ! 259: ! 260: deviceContext = connection->Provider; ! 261: ! 262: parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&irpSp->Parameters; ! 263: ! 264: // ! 265: // get a pointer to the address File Object, which points us to the ! 266: // transport's address object, which is where we want to put the ! 267: // connection. ! 268: // ! 269: ! 270: status = ObReferenceObjectByHandle ( ! 271: parameters->AddressHandle, ! 272: 0L, ! 273: 0, ! 274: KernelMode, ! 275: (PVOID *) &fileObject, ! 276: NULL); ! 277: ! 278: if (NT_SUCCESS(status)) { ! 279: ! 280: // ! 281: // we might have one of our address objects; verify that. ! 282: // ! 283: ! 284: addressFile = fileObject->FsContext; ! 285: ! 286: if (NT_SUCCESS (StVerifyAddressObject (addressFile))) { ! 287: ! 288: // ! 289: // have an address and connection object. Add the connection to the ! 290: // address object database. Also add the connection to the address ! 291: // file object db (used primarily for cleaning up). Reference the ! 292: // address to account for one more reason for it staying open. ! 293: // ! 294: ! 295: ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql); ! 296: if ((addressFile->Address->Flags & ADDRESS_FLAGS_STOPPING) == 0) { ! 297: ! 298: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2); ! 299: ! 300: if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) { ! 301: ! 302: StReferenceAddress ( ! 303: "Connection associated", ! 304: addressFile->Address); ! 305: ! 306: InsertTailList ( ! 307: &addressFile->Address->ConnectionDatabase, ! 308: &connection->AddressList); ! 309: ! 310: InsertTailList ( ! 311: &addressFile->ConnectionDatabase, ! 312: &connection->AddressFileList); ! 313: ! 314: connection->AddressFile = addressFile; ! 315: connection->Flags2 |= CONNECTION_FLAGS2_ASSOCIATED; ! 316: connection->Flags2 &= ~CONNECTION_FLAGS2_DISASSOCIATED; ! 317: ! 318: if (addressFile->ConnectIndicationInProgress) { ! 319: connection->Flags2 |= CONNECTION_FLAGS2_INDICATING; ! 320: } ! 321: ! 322: status = STATUS_SUCCESS; ! 323: ! 324: } else { ! 325: ! 326: // ! 327: // The connection is closing, stop the ! 328: // association. ! 329: // ! 330: ! 331: status = STATUS_INVALID_CONNECTION; ! 332: ! 333: } ! 334: ! 335: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2); ! 336: ! 337: } else { ! 338: ! 339: status = STATUS_INVALID_HANDLE; ! 340: } ! 341: ! 342: RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql); ! 343: ! 344: StDereferenceAddress ("Temp associate", addressFile->Address); ! 345: ! 346: } else { ! 347: ! 348: status = STATUS_INVALID_HANDLE; ! 349: } ! 350: ! 351: // ! 352: // Note that we don't keep a reference to this file object around. ! 353: // That's because the IO subsystem manages the object for us; we simply ! 354: // want to keep the association. We only use this association when the ! 355: // IO subsystem has asked us to close one of the file object, and then ! 356: // we simply remove the association. ! 357: // ! 358: ! 359: ObDereferenceObject (fileObject); ! 360: ! 361: } else { ! 362: status = STATUS_INVALID_HANDLE; ! 363: } ! 364: ! 365: StDereferenceConnection ("Temp Ref Associate", connection); ! 366: ! 367: return status; ! 368: ! 369: } /* TdiAssociateAddress */ ! 370: ! 371: ! 372: NTSTATUS ! 373: StTdiDisassociateAddress( ! 374: IN PIRP Irp ! 375: ) ! 376: /*++ ! 377: ! 378: Routine Description: ! 379: ! 380: This routine performs the disassociation of the connection and the address ! 381: for the user. If the connection has not been stopped, it will be stopped ! 382: here. ! 383: ! 384: Arguments: ! 385: ! 386: Irp - Pointer to the I/O Request Packet for this request. ! 387: ! 388: Return Value: ! 389: ! 390: NTSTATUS - status of operation. ! 391: ! 392: --*/ ! 393: ! 394: { ! 395: ! 396: KIRQL oldirql; ! 397: PIO_STACK_LOCATION irpSp; ! 398: PTP_CONNECTION connection; ! 399: NTSTATUS status; ! 400: ! 401: irpSp = IoGetCurrentIrpStackLocation (Irp); ! 402: ! 403: connection = irpSp->FileObject->FsContext; ! 404: ! 405: // ! 406: // If successful this adds a reference. ! 407: // ! 408: ! 409: status = StVerifyConnectionObject (connection); ! 410: ! 411: if (!NT_SUCCESS (status)) { ! 412: return status; ! 413: } ! 414: ! 415: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql); ! 416: if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) { ! 417: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 418: StStopConnection (connection, STATUS_LOCAL_DISCONNECT); ! 419: ! 420: } else { ! 421: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 422: } ! 423: ! 424: // ! 425: // and now we disassociate the address. This only removes ! 426: // the appropriate reference for the connection, the ! 427: // actually disassociation will be done later. ! 428: // ! 429: // The DISASSOCIATED flag is used to make sure that ! 430: // only one person removes this reference. ! 431: // ! 432: ! 433: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql); ! 434: if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) && ! 435: ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) { ! 436: connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED; ! 437: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 438: } else { ! 439: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 440: } ! 441: ! 442: StDereferenceConnection ("Temp use in Associate", connection); ! 443: ! 444: return STATUS_SUCCESS; ! 445: ! 446: } /* TdiDisassociateAddress */ ! 447: ! 448: ! 449: NTSTATUS ! 450: StTdiConnect( ! 451: IN PIRP Irp ! 452: ) ! 453: ! 454: /*++ ! 455: ! 456: Routine Description: ! 457: ! 458: This routine performs the TdiConnect request for the transport provider. ! 459: ! 460: Arguments: ! 461: ! 462: Irp - Pointer to the I/O Request Packet for this request. ! 463: ! 464: Return Value: ! 465: ! 466: NTSTATUS - status of operation. ! 467: ! 468: --*/ ! 469: ! 470: { ! 471: NTSTATUS status; ! 472: PTP_CONNECTION connection; ! 473: PSTRING GeneralBroadcastSourceRoute = NULL; // BUGBUG: define this later. ! 474: LARGE_INTEGER timeout = {0,0}; ! 475: KIRQL oldirql, cancelirql; ! 476: PTP_REQUEST tpRequest; ! 477: PIO_STACK_LOCATION irpSp; ! 478: PTDI_REQUEST_KERNEL parameters; ! 479: PTA_NETBIOS_ADDRESS RemoteAddress; ! 480: ULONG RemoteAddressLength; ! 481: ! 482: // ! 483: // is the file object a connection? ! 484: // ! 485: ! 486: irpSp = IoGetCurrentIrpStackLocation (Irp); ! 487: connection = irpSp->FileObject->FsContext; ! 488: ! 489: // ! 490: // If successful this adds a reference. ! 491: // ! 492: ! 493: status = StVerifyConnectionObject (connection); ! 494: ! 495: if (!NT_SUCCESS (status)) { ! 496: return status; ! 497: } ! 498: ! 499: parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters); ! 500: ! 501: // ! 502: // fix up the timeout if required; no connect request should take more ! 503: // than 15 seconds if there is someone out there. We'll assume that's ! 504: // what the user wanted if they specify -1 as the timer length. ! 505: // ! 506: ! 507: if (parameters->RequestSpecific != NULL) { ! 508: if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) && ! 509: (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) { ! 510: ! 511: timeout.LowPart = (ULONG)(-TDI_TIMEOUT_CONNECT * 10000000L); // n * 10 ** 7 => 100ns units ! 512: if (timeout.LowPart != 0) { ! 513: timeout.HighPart = -1L; ! 514: } else { ! 515: timeout.HighPart = 0; ! 516: } ! 517: ! 518: } else { ! 519: ! 520: timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart; ! 521: timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart; ! 522: } ! 523: } ! 524: ! 525: // ! 526: // Check that the remote is a Netbios address. ! 527: // ! 528: ! 529: RemoteAddress = (PTA_NETBIOS_ADDRESS) ! 530: (parameters->RequestConnectionInformation->RemoteAddress); ! 531: ! 532: if (RemoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_NETBIOS) { ! 533: ! 534: StDereferenceConnection ("Not Netbios", connection); ! 535: return STATUS_BAD_NETWORK_PATH; // don't even try to find it. ! 536: ! 537: } ! 538: ! 539: // ! 540: // copy the called address someplace we can use it. ! 541: // ! 542: ! 543: RemoteAddressLength = parameters->RequestConnectionInformation->RemoteAddressLength; ! 544: ! 545: if (RemoteAddressLength > sizeof(TA_NETBIOS_ADDRESS)) { ! 546: RemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS); ! 547: } ! 548: ! 549: RtlCopyMemory( ! 550: connection->CalledAddress.NetbiosName, ! 551: RemoteAddress->Address[0].Address[0].NetbiosName, ! 552: 16); ! 553: ! 554: // ! 555: // We need a request object to keep track of this TDI request. ! 556: // Attach this request to the new connection object. ! 557: // ! 558: ! 559: status = StCreateRequest ( ! 560: Irp, // IRP for this request. ! 561: connection, // context. ! 562: REQUEST_FLAGS_CONNECTION, // partial flags. ! 563: NULL, ! 564: 0, ! 565: timeout, ! 566: &tpRequest); ! 567: ! 568: if (!NT_SUCCESS (status)) { // couldn't make the request. ! 569: StDereferenceConnection ("Throw away", connection); ! 570: return status; // return with failure. ! 571: } else { ! 572: ! 573: // Reference the connection since StDestroyRequest derefs it. ! 574: ! 575: StReferenceConnection("For connect request", connection); ! 576: ! 577: tpRequest->Owner = ConnectionType; ! 578: IoAcquireCancelSpinLock (&cancelirql); ! 579: ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql); ! 580: if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) { ! 581: RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql); ! 582: IoReleaseCancelSpinLock (cancelirql); ! 583: StCompleteRequest ( ! 584: tpRequest, ! 585: connection->Status, ! 586: 0); ! 587: StDereferenceConnection("Temporary Use 1", connection); ! 588: return STATUS_PENDING; ! 589: } else { ! 590: InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage); ! 591: ! 592: connection->Flags |= CONNECTION_FLAGS_CONNECTOR; // we're the initiator. ! 593: ! 594: connection->Flags &= ~CONNECTION_FLAGS_STOPPING; ! 595: connection->Status = STATUS_PENDING; ! 596: ! 597: connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING; ! 598: RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql); ! 599: ! 600: // ! 601: // Check if the IRP has been cancelled. ! 602: // ! 603: ! 604: if (Irp->Cancel) { ! 605: Irp->CancelIrql = cancelirql; ! 606: StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp); ! 607: StDereferenceConnection ("IRP cancelled", connection); // release lookup hold. ! 608: return STATUS_PENDING; ! 609: } ! 610: ! 611: Irp->CancelRoutine = StCancelConnection; ! 612: IoReleaseCancelSpinLock(cancelirql); ! 613: ! 614: } ! 615: } ! 616: ! 617: status = StSendConnect ( ! 618: connection); ! 619: ! 620: if (!NT_SUCCESS(status)) { // can't send the name request ! 621: StStopConnection (connection, status); ! 622: StDereferenceConnection("Temporary Use 2", connection); ! 623: ! 624: // ! 625: // Note that this return status isn't really a lie. We are waiting ! 626: // for the connection to run down. ! 627: // ! 628: ! 629: return STATUS_PENDING; ! 630: } ! 631: ! 632: ! 633: StDereferenceConnection("Temporary Use 3", connection); ! 634: ! 635: return STATUS_PENDING; // things are started. ! 636: ! 637: } /* TdiConnect */ ! 638: ! 639: ! 640: NTSTATUS ! 641: StTdiDisconnect( ! 642: IN PIRP Irp ! 643: ) ! 644: ! 645: /*++ ! 646: ! 647: Routine Description: ! 648: ! 649: This routine performs the TdiDisconnect request for the transport provider. ! 650: ! 651: Arguments: ! 652: ! 653: Irp - Pointer to the I/O Request Packet for this request. ! 654: ! 655: Return Value: ! 656: ! 657: NTSTATUS - status of operation. ! 658: ! 659: --*/ ! 660: ! 661: { ! 662: PTP_CONNECTION connection; ! 663: LARGE_INTEGER timeout; ! 664: PIO_STACK_LOCATION irpSp; ! 665: PTDI_REQUEST_KERNEL parameters; ! 666: KIRQL oldirql; ! 667: NTSTATUS status; ! 668: ! 669: ! 670: irpSp = IoGetCurrentIrpStackLocation (Irp); ! 671: ! 672: connection = irpSp->FileObject->FsContext; ! 673: ! 674: // ! 675: // If successful this adds a reference. ! 676: // ! 677: ! 678: status = StVerifyConnectionObject (connection); ! 679: if (!NT_SUCCESS (status)) { ! 680: return status; ! 681: } ! 682: ! 683: ! 684: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql); ! 685: ! 686: // ! 687: // if the connection is currently stopping, there's no reason to blow ! 688: // it away... ! 689: // ! 690: ! 691: if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) { ! 692: ! 693: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 694: StDereferenceConnection ("Ignoring disconnect", connection); // release our lookup reference. ! 695: return connection->Status; ! 696: ! 697: } else { ! 698: connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED | ! 699: CONNECTION_FLAGS2_PRE_ACCEPT | ! 700: CONNECTION_FLAGS2_WAIT_ACCEPT); ! 701: connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT; ! 702: ! 703: // ! 704: // Set this flag so the disconnect IRP is completed. ! 705: // ! 706: // BUGBUG: If the connection goes down before we can ! 707: // call StStopConnection with STATUS_LOCAL_DISCONNECT, ! 708: // the disconnect IRP won't get completed. ! 709: // ! 710: ! 711: connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED; ! 712: ! 713: connection->DisconnectIrp = Irp; ! 714: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 715: } ! 716: ! 717: // ! 718: // fix up the timeout if required; no disconnect request should take very ! 719: // long. However, the user can cause the timeout to not happen if they ! 720: // desire that. ! 721: // ! 722: ! 723: parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters); ! 724: ! 725: // ! 726: // fix up the timeout if required; no disconnect request should take more ! 727: // than 15 seconds. We'll assume that's what the user wanted if they ! 728: // specify -1 as the timer. ! 729: // ! 730: ! 731: if (parameters->RequestSpecific != NULL) { ! 732: if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) && ! 733: (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) { ! 734: ! 735: timeout.LowPart = (ULONG)(-TDI_TIMEOUT_DISCONNECT * 10000000L); // n * 10 ** 7 => 100ns units ! 736: if (timeout.LowPart != 0) { ! 737: timeout.HighPart = -1L; ! 738: } else { ! 739: timeout.HighPart = 0; ! 740: } ! 741: ! 742: } else { ! 743: timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart; ! 744: timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart; ! 745: } ! 746: } ! 747: ! 748: // ! 749: // Now the reason for the disconnect ! 750: // ! 751: ! 752: if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_RELEASE) { ! 753: connection->Flags |= CONNECTION_FLAGS_DESTROY; ! 754: } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) { ! 755: connection->Flags |= CONNECTION_FLAGS_ABORT; ! 756: } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) { ! 757: connection->Flags |= CONNECTION_FLAGS_ORDREL; ! 758: } ! 759: ! 760: // ! 761: // This will get passed to IoCompleteRequest during TdiDestroyConnection ! 762: // ! 763: ! 764: StStopConnection (connection, STATUS_LOCAL_DISCONNECT); // starts the abort sequence. ! 765: StDereferenceConnection ("Disconnecting", connection); // release our lookup reference. ! 766: ! 767: // ! 768: // This request will be completed by TdiDestroyConnection once ! 769: // the connection reference count drops to 0. ! 770: // ! 771: ! 772: return STATUS_PENDING; ! 773: } /* TdiDisconnect */ ! 774: ! 775: ! 776: NTSTATUS ! 777: StTdiListen( ! 778: IN PIRP Irp ! 779: ) ! 780: ! 781: /*++ ! 782: ! 783: Routine Description: ! 784: ! 785: This routine performs the TdiListen request for the transport provider. ! 786: ! 787: Arguments: ! 788: ! 789: Irp - Pointer to the I/O Request Packet for this request. ! 790: ! 791: Return Value: ! 792: ! 793: NTSTATUS - status of operation. ! 794: ! 795: --*/ ! 796: ! 797: { ! 798: NTSTATUS status; ! 799: PTP_CONNECTION connection; ! 800: LARGE_INTEGER timeout = {0,0}; ! 801: KIRQL oldirql, cancelirql; ! 802: PTP_REQUEST tpRequest; ! 803: PIO_STACK_LOCATION irpSp; ! 804: PTDI_REQUEST_KERNEL_LISTEN parameters; ! 805: ! 806: // ! 807: // validate this connection ! 808: ! 809: irpSp = IoGetCurrentIrpStackLocation (Irp); ! 810: ! 811: connection = irpSp->FileObject->FsContext; ! 812: ! 813: // ! 814: // If successful this adds a reference. ! 815: // ! 816: ! 817: status = StVerifyConnectionObject (connection); ! 818: ! 819: if (!NT_SUCCESS (status)) { ! 820: return status; ! 821: } ! 822: ! 823: parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters; ! 824: ! 825: // ! 826: // We need a request object to keep track of this TDI request. ! 827: // Attach this request to the new connection object. ! 828: // ! 829: ! 830: status = StCreateRequest ( ! 831: Irp, // IRP for this request. ! 832: connection, // context. ! 833: REQUEST_FLAGS_CONNECTION, // partial flags. ! 834: NULL, ! 835: 0, ! 836: timeout, // timeout value (can be 0). ! 837: &tpRequest); ! 838: ! 839: ! 840: if (!NT_SUCCESS (status)) { // couldn't make the request. ! 841: ! 842: StDereferenceConnection ("For create", connection); ! 843: return status; // return with failure. ! 844: } ! 845: ! 846: // Reference the connection since StDestroyRequest derefs it. ! 847: ! 848: IoAcquireCancelSpinLock (&cancelirql); ! 849: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql); ! 850: tpRequest->Owner = ConnectionType; ! 851: ! 852: StReferenceConnection("For listen request", connection); ! 853: ! 854: if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) { ! 855: ! 856: RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql); ! 857: IoReleaseCancelSpinLock(cancelirql); ! 858: ! 859: StCompleteRequest ( ! 860: tpRequest, ! 861: connection->Status, ! 862: 0); ! 863: StDereferenceConnection("Temp create", connection); ! 864: return STATUS_PENDING; ! 865: ! 866: } else { ! 867: ! 868: InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage); ! 869: connection->Flags |= CONNECTION_FLAGS_LISTENER | // we're the passive one. ! 870: CONNECTION_FLAGS_WAIT_LISTEN; // waiting for a connect ! 871: connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING; ! 872: connection->Flags &= ~CONNECTION_FLAGS_STOPPING; ! 873: connection->Status = STATUS_PENDING; ! 874: ! 875: // ! 876: // If TDI_QUERY_ACCEPT is not set, then we set PRE_ACCEPT to ! 877: // indicate that when the listen completes we do not have to ! 878: // wait for a TDI_ACCEPT to continue. ! 879: // ! 880: ! 881: if ((parameters->RequestFlags & TDI_QUERY_ACCEPT) == 0) { ! 882: connection->Flags2 |= CONNECTION_FLAGS2_PRE_ACCEPT; ! 883: } ! 884: ! 885: RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql); ! 886: ! 887: // ! 888: // Check if the IRP has been cancelled. ! 889: // ! 890: ! 891: if (Irp->Cancel) { ! 892: Irp->CancelIrql = cancelirql; ! 893: StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp); ! 894: StDereferenceConnection ("IRP cancelled", connection); // release lookup hold. ! 895: return STATUS_PENDING; ! 896: } ! 897: ! 898: Irp->CancelRoutine = StCancelConnection; ! 899: IoReleaseCancelSpinLock(cancelirql); ! 900: ! 901: } ! 902: ! 903: // ! 904: // Wait for an incoming NAME_QUERY frame. The remainder of the ! 905: // connectionless protocol to set up a connection is processed ! 906: // in the NAME_QUERY frame handler. ! 907: // ! 908: ! 909: StDereferenceConnection("Temp create", connection); ! 910: ! 911: return STATUS_PENDING; // things are started. ! 912: } /* TdiListen */ ! 913: ! 914: ! 915: NTSTATUS ! 916: StOpenConnection ( ! 917: IN PDEVICE_OBJECT DeviceObject, ! 918: IN PIRP Irp, ! 919: IN PIO_STACK_LOCATION IrpSp ! 920: ) ! 921: ! 922: /*++ ! 923: ! 924: Routine Description: ! 925: ! 926: This routine is called to open a connection. Note that the connection that ! 927: is open is of little use until associated with an address; until then, ! 928: the only thing that can be done with it is close it. ! 929: ! 930: Arguments: ! 931: ! 932: DeviceObject - Pointer to the device object for this driver. ! 933: ! 934: Irp - Pointer to the request packet representing the I/O request. ! 935: ! 936: IrpSp - Pointer to current IRP stack frame. ! 937: ! 938: Return Value: ! 939: ! 940: The function value is the status of the operation. ! 941: ! 942: --*/ ! 943: ! 944: { ! 945: PDEVICE_CONTEXT DeviceContext; ! 946: NTSTATUS status; ! 947: PTP_CONNECTION connection; ! 948: PFILE_FULL_EA_INFORMATION ea; ! 949: ! 950: UNREFERENCED_PARAMETER (Irp); ! 951: ! 952: DeviceContext = (PDEVICE_CONTEXT)DeviceObject; ! 953: ! 954: // ! 955: // First, try to make a connection object to represent this pending ! 956: // connection. Then fill in the relevant fields. ! 957: // In addition to the creation, if successful StCreateConnection ! 958: // will create a second reference which is removed once the request ! 959: // references the connection, or if the function exits before that. ! 960: ! 961: status = StCreateConnection (DeviceContext, &connection); ! 962: if (!NT_SUCCESS (status)) { ! 963: return status; // sorry, we couldn't make one. ! 964: } ! 965: ! 966: // ! 967: // set the connection context so we can connect the user to this data ! 968: // structure ! 969: // ! 970: ! 971: ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ! 972: RtlCopyMemory ( ! 973: &connection->Context, ! 974: &ea->EaName[ea->EaNameLength+1], ! 975: sizeof (PVOID)); ! 976: ! 977: // ! 978: // let file object point at connection and connection at file object ! 979: // ! 980: ! 981: IrpSp->FileObject->FsContext = (PVOID)connection; ! 982: IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE; ! 983: connection->FileObject = IrpSp->FileObject; ! 984: ! 985: return status; ! 986: ! 987: } /* StOpenConnection */ ! 988: ! 989: ! 990: NTSTATUS ! 991: StCloseConnection ( ! 992: IN PDEVICE_OBJECT DeviceObject, ! 993: IN PIRP Irp, ! 994: IN PIO_STACK_LOCATION IrpSp ! 995: ) ! 996: ! 997: /*++ ! 998: ! 999: Routine Description: ! 1000: ! 1001: This routine is called to close a connection. There may be actions in ! 1002: progress on this connection, so we note the closing IRP, mark the ! 1003: connection as closing, and complete it somewhere down the road (when all ! 1004: references have been removed). ! 1005: ! 1006: Arguments: ! 1007: ! 1008: DeviceObject - Pointer to the device object for this driver. ! 1009: ! 1010: Irp - Pointer to the request packet representing the I/O request. ! 1011: ! 1012: IrpSp - Pointer to current IRP stack frame. ! 1013: ! 1014: Return Value: ! 1015: ! 1016: The function value is the status of the operation. ! 1017: ! 1018: --*/ ! 1019: ! 1020: { ! 1021: NTSTATUS status; ! 1022: KIRQL oldirql; ! 1023: PTP_CONNECTION connection; ! 1024: ! 1025: UNREFERENCED_PARAMETER (DeviceObject); ! 1026: UNREFERENCED_PARAMETER (Irp); ! 1027: ! 1028: // ! 1029: // is the file object a connection? ! 1030: // ! 1031: ! 1032: connection = IrpSp->FileObject->FsContext; ! 1033: ! 1034: ! 1035: // ! 1036: // We duplicate the code from VerifyConnectionObject, ! 1037: // although we don't actually call that since it does ! 1038: // a reference, which we don't want (to avoid bouncing ! 1039: // the reference count up from 0 if this is a dead ! 1040: // link). ! 1041: // ! 1042: ! 1043: try { ! 1044: ! 1045: if ((connection->Size == sizeof (TP_CONNECTION)) && ! 1046: (connection->Type == ST_CONNECTION_SIGNATURE)) { ! 1047: ! 1048: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql); ! 1049: ! 1050: if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) { ! 1051: ! 1052: status = STATUS_SUCCESS; ! 1053: ! 1054: } else { ! 1055: ! 1056: status = STATUS_INVALID_CONNECTION; ! 1057: } ! 1058: ! 1059: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 1060: ! 1061: } else { ! 1062: ! 1063: status = STATUS_INVALID_CONNECTION; ! 1064: } ! 1065: ! 1066: } except(EXCEPTION_EXECUTE_HANDLER) { ! 1067: ! 1068: return GetExceptionCode(); ! 1069: } ! 1070: ! 1071: if (!NT_SUCCESS (status)) { ! 1072: return status; ! 1073: } ! 1074: ! 1075: // ! 1076: // We recognize it; is it closing already? ! 1077: // ! 1078: ! 1079: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql); ! 1080: ! 1081: if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) { ! 1082: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 1083: StDereferenceConnection("Temp Close", connection); ! 1084: return STATUS_INVALID_CONNECTION; ! 1085: } ! 1086: ! 1087: connection->Flags2 |= CONNECTION_FLAGS2_CLOSING; ! 1088: ! 1089: // ! 1090: // if there is activity on the connection, tear it down. ! 1091: // ! 1092: ! 1093: if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) { ! 1094: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 1095: StStopConnection (connection, STATUS_LOCAL_DISCONNECT); ! 1096: ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql); ! 1097: } ! 1098: ! 1099: // ! 1100: // If the connection is still associated, disassociate it. ! 1101: // ! 1102: ! 1103: if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) && ! 1104: ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) { ! 1105: connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED; ! 1106: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 1107: } else { ! 1108: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql); ! 1109: } ! 1110: ! 1111: ! 1112: // ! 1113: // Save this to complete the IRP later. ! 1114: // ! 1115: ! 1116: connection->CloseIrp = Irp; ! 1117: ! 1118: // ! 1119: // make it impossible to use this connection from the file object ! 1120: // ! 1121: ! 1122: IrpSp->FileObject->FsContext = NULL; ! 1123: IrpSp->FileObject->FsContext2 = NULL; ! 1124: connection->FileObject = NULL; ! 1125: ! 1126: // ! 1127: // dereference for the creation. Note that this dereference ! 1128: // here won't have any effect until the regular reference count ! 1129: // hits zero. ! 1130: // ! 1131: ! 1132: StDereferenceConnectionSpecial (" Closing Connection", connection); ! 1133: ! 1134: return STATUS_PENDING; ! 1135: ! 1136: } /* StCloseConnection */ ! 1137:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.