|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1989-1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: connobj.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains code which implements the TP_CONNECTION object. ! 12: Routines are provided to create, destroy, reference, and dereference, ! 13: transport connection objects. ! 14: ! 15: Environment: ! 16: ! 17: Kernel mode ! 18: ! 19: Revision History: ! 20: ! 21: --*/ ! 22: ! 23: #include "st.h" ! 24: ! 25: ! 26: ! 27: VOID ! 28: StAllocateConnection( ! 29: IN PDEVICE_CONTEXT DeviceContext, ! 30: OUT PTP_CONNECTION *TransportConnection ! 31: ) ! 32: ! 33: /*++ ! 34: ! 35: Routine Description: ! 36: ! 37: This routine allocates storage for a transport connection. Some ! 38: minimal initialization is done. ! 39: ! 40: NOTE: This routine is called with the device context spinlock ! 41: held, or at such a time as synchronization is unnecessary. ! 42: ! 43: Arguments: ! 44: ! 45: DeviceContext - the device context for this connection to be ! 46: associated with. ! 47: ! 48: TransportConnection - Pointer to a place where this routine will ! 49: return a pointer to a transport connection structure. Returns ! 50: NULL if the storage cannot be allocated. ! 51: ! 52: Return Value: ! 53: ! 54: None. ! 55: ! 56: --*/ ! 57: ! 58: { ! 59: ! 60: PTP_CONNECTION Connection; ! 61: ! 62: if ((DeviceContext->MemoryLimit != 0) && ! 63: ((DeviceContext->MemoryUsage + sizeof(TP_CONNECTION)) > ! 64: DeviceContext->MemoryLimit)) { ! 65: PANIC("ST: Could not allocate connection: limit\n"); ! 66: StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 103); ! 67: *TransportConnection = NULL; ! 68: return; ! 69: } ! 70: ! 71: Connection = (PTP_CONNECTION)ExAllocatePool (NonPagedPool, ! 72: sizeof (TP_CONNECTION)); ! 73: if (Connection == NULL) { ! 74: PANIC("ST: Could not allocate connection: no pool\n"); ! 75: StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 203); ! 76: *TransportConnection = NULL; ! 77: return; ! 78: } ! 79: RtlZeroMemory (Connection, sizeof(TP_CONNECTION)); ! 80: ! 81: DeviceContext->MemoryUsage += sizeof(TP_CONNECTION); ! 82: ++DeviceContext->ConnectionAllocated; ! 83: ! 84: Connection->Type = ST_CONNECTION_SIGNATURE; ! 85: Connection->Size = sizeof (TP_CONNECTION); ! 86: ! 87: Connection->Provider = DeviceContext; ! 88: Connection->ProviderInterlock = &DeviceContext->Interlock; ! 89: KeInitializeSpinLock (&Connection->SpinLock); ! 90: ! 91: InitializeListHead (&Connection->LinkList); ! 92: InitializeListHead (&Connection->AddressFileList); ! 93: InitializeListHead (&Connection->AddressList); ! 94: InitializeListHead (&Connection->PacketWaitLinkage); ! 95: InitializeListHead (&Connection->PacketizeLinkage); ! 96: InitializeListHead (&Connection->SendQueue); ! 97: InitializeListHead (&Connection->ReceiveQueue); ! 98: InitializeListHead (&Connection->InProgressRequest); ! 99: ! 100: StAddSendPacket (DeviceContext); ! 101: ! 102: *TransportConnection = Connection; ! 103: ! 104: } /* StAllocateConnection */ ! 105: ! 106: ! 107: VOID ! 108: StDeallocateConnection( ! 109: IN PDEVICE_CONTEXT DeviceContext, ! 110: IN PTP_CONNECTION TransportConnection ! 111: ) ! 112: ! 113: /*++ ! 114: ! 115: Routine Description: ! 116: ! 117: This routine frees storage for a transport connection. ! 118: ! 119: NOTE: This routine is called with the device context spinlock ! 120: held, or at such a time as synchronization is unnecessary. ! 121: ! 122: Arguments: ! 123: ! 124: DeviceContext - the device context for this connection to be ! 125: associated with. ! 126: ! 127: TransportConnection - Pointer to a transport connection structure. ! 128: ! 129: Return Value: ! 130: ! 131: None. ! 132: ! 133: --*/ ! 134: ! 135: { ! 136: ! 137: ExFreePool (TransportConnection); ! 138: --DeviceContext->ConnectionAllocated; ! 139: DeviceContext->MemoryUsage -= sizeof(TP_CONNECTION); ! 140: ! 141: StRemoveSendPacket (DeviceContext); ! 142: ! 143: } /* StDeallocateConnection */ ! 144: ! 145: ! 146: NTSTATUS ! 147: StCreateConnection( ! 148: IN PDEVICE_CONTEXT DeviceContext, ! 149: OUT PTP_CONNECTION *TransportConnection ! 150: ) ! 151: ! 152: /*++ ! 153: ! 154: Routine Description: ! 155: ! 156: This routine creates a transport connection. The reference count in the ! 157: connection is automatically set to 1, and the reference count in the ! 158: DeviceContext is incremented. ! 159: ! 160: Arguments: ! 161: ! 162: Address - the address for this connection to be associated with. ! 163: ! 164: TransportConnection - Pointer to a place where this routine will ! 165: return a pointer to a transport connection structure. ! 166: ! 167: Return Value: ! 168: ! 169: NTSTATUS - status of operation. ! 170: ! 171: --*/ ! 172: ! 173: { ! 174: PTP_CONNECTION Connection; ! 175: KIRQL oldirql; ! 176: PLIST_ENTRY p; ! 177: UINT TempDataLen; ! 178: ! 179: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql); ! 180: ! 181: p = RemoveHeadList (&DeviceContext->ConnectionPool); ! 182: if (p == &DeviceContext->ConnectionPool) { ! 183: ! 184: if ((DeviceContext->ConnectionMaxAllocated == 0) || ! 185: (DeviceContext->ConnectionAllocated < DeviceContext->ConnectionMaxAllocated)) { ! 186: ! 187: StAllocateConnection (DeviceContext, &Connection); ! 188: ! 189: } else { ! 190: ! 191: StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 403); ! 192: Connection = NULL; ! 193: ! 194: } ! 195: ! 196: if (Connection == NULL) { ! 197: ++DeviceContext->ConnectionExhausted; ! 198: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); ! 199: PANIC ("StCreateConnection: Could not allocate connection object!\n"); ! 200: return STATUS_INSUFFICIENT_RESOURCES; ! 201: } ! 202: ! 203: } else { ! 204: ! 205: Connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList); ! 206: ! 207: } ! 208: ! 209: ++DeviceContext->ConnectionInUse; ! 210: if (DeviceContext->ConnectionInUse > DeviceContext->ConnectionMaxInUse) { ! 211: ++DeviceContext->ConnectionMaxInUse; ! 212: } ! 213: ! 214: DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse; ! 215: ++DeviceContext->ConnectionSamples; ! 216: ! 217: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); ! 218: ! 219: ! 220: // ! 221: // We have two references; one is for creation, and the ! 222: // other is a temporary one so that the connection won't ! 223: // go away before the creator has a chance to access it. ! 224: // ! 225: ! 226: Connection->SpecialRefCount = 1; ! 227: Connection->ReferenceCount = -1; // this is -1 based ! 228: ! 229: // ! 230: // Initialize the request queues & components of this connection. ! 231: // ! 232: ! 233: InitializeListHead (&Connection->SendQueue); ! 234: InitializeListHead (&Connection->ReceiveQueue); ! 235: InitializeListHead (&Connection->InProgressRequest); ! 236: InitializeListHead (&Connection->AddressList); ! 237: InitializeListHead (&Connection->AddressFileList); ! 238: Connection->SpecialReceiveIrp = (PIRP)NULL; ! 239: Connection->Flags = 0; ! 240: Connection->Flags2 = 0; ! 241: Connection->MessageBytesReceived = (USHORT)0; // no data yet ! 242: Connection->MessageBytesAcked = (USHORT)0; ! 243: Connection->Context = NULL; // no context yet. ! 244: Connection->Status = STATUS_PENDING; // default StStopConnection status. ! 245: Connection->SendState = CONNECTION_SENDSTATE_IDLE; ! 246: Connection->CurrentReceiveRequest = (PTP_REQUEST)NULL; ! 247: Connection->DisconnectIrp = (PIRP)NULL; ! 248: Connection->CloseIrp = (PIRP)NULL; ! 249: Connection->AddressFile = NULL; ! 250: Connection->IndicationInProgress = FALSE; ! 251: ! 252: MacReturnMaxDataSize( ! 253: &DeviceContext->MacInfo, ! 254: NULL, ! 255: 0, ! 256: DeviceContext->MaxSendPacketSize, ! 257: &TempDataLen); ! 258: Connection->MaximumDataSize = TempDataLen - sizeof(ST_HEADER); ! 259: ! 260: StReferenceDeviceContext ("Create Connection", DeviceContext); ! 261: ! 262: *TransportConnection = Connection; // return the connection. ! 263: ! 264: return STATUS_SUCCESS; ! 265: } /* StCreateConnection */ ! 266: ! 267: ! 268: NTSTATUS ! 269: StVerifyConnectionObject ( ! 270: IN PTP_CONNECTION Connection ! 271: ) ! 272: ! 273: /*++ ! 274: ! 275: Routine Description: ! 276: ! 277: This routine is called to verify that the pointer given us in a file ! 278: object is in fact a valid connection object. ! 279: ! 280: Arguments: ! 281: ! 282: Connection - potential pointer to a TP_CONNECTION object. ! 283: ! 284: Return Value: ! 285: ! 286: STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise ! 287: ! 288: --*/ ! 289: ! 290: { ! 291: KIRQL oldirql; ! 292: NTSTATUS status = STATUS_SUCCESS; ! 293: ! 294: // ! 295: // try to verify the connection signature. If the signature is valid, ! 296: // get the connection spinlock, check its state, and increment the ! 297: // reference count if it's ok to use it. Note that being in the stopping ! 298: // state is an OK place to be and reference the connection; we can ! 299: // disassociate the address while running down. ! 300: // ! 301: ! 302: try { ! 303: ! 304: if ((Connection->Size == sizeof (TP_CONNECTION)) && ! 305: (Connection->Type == ST_CONNECTION_SIGNATURE)) { ! 306: ! 307: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 308: ! 309: if ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) { ! 310: ! 311: StReferenceConnection ("Verify Temp Use", Connection); ! 312: ! 313: } else { ! 314: ! 315: status = STATUS_INVALID_CONNECTION; ! 316: } ! 317: ! 318: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 319: ! 320: } else { ! 321: ! 322: status = STATUS_INVALID_CONNECTION; ! 323: } ! 324: ! 325: } except(EXCEPTION_EXECUTE_HANDLER) { ! 326: ! 327: return GetExceptionCode(); ! 328: } ! 329: ! 330: return status; ! 331: ! 332: } ! 333: ! 334: ! 335: NTSTATUS ! 336: StDestroyAssociation( ! 337: IN PTP_CONNECTION TransportConnection ! 338: ) ! 339: ! 340: /*++ ! 341: ! 342: Routine Description: ! 343: ! 344: This routine destroys the association between a transport connection and ! 345: the address it was formerly associated with. The only action taken is ! 346: to disassociate the address and remove the connection from all address ! 347: queues. ! 348: ! 349: This routine is only called by StDereferenceConnection. The reason for ! 350: this is that there may be multiple streams of execution which are ! 351: simultaneously referencing the same connection object, and it should ! 352: not be deleted out from under an interested stream of execution. ! 353: ! 354: Arguments: ! 355: ! 356: TransportConnection - Pointer to a transport connection structure to ! 357: be destroyed. ! 358: ! 359: Return Value: ! 360: ! 361: NTSTATUS - status of operation. ! 362: ! 363: --*/ ! 364: ! 365: { ! 366: KIRQL oldirql, oldirql2; ! 367: PTP_ADDRESS_FILE addressFile; ! 368: ! 369: ! 370: ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2); ! 371: if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) { ! 372: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2); ! 373: return STATUS_SUCCESS; ! 374: } else { ! 375: TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED; ! 376: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2); ! 377: } ! 378: ! 379: addressFile = TransportConnection->AddressFile; ! 380: ! 381: // ! 382: // Delink this connection from its associated address connection ! 383: // database. To do this we must spin lock on the address object as ! 384: // well as on the connection, ! 385: // ! 386: ! 387: ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql); ! 388: ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2); ! 389: RemoveEntryList (&TransportConnection->AddressFileList); ! 390: RemoveEntryList (&TransportConnection->AddressList); ! 391: ! 392: InitializeListHead (&TransportConnection->AddressList); ! 393: InitializeListHead (&TransportConnection->AddressFileList); ! 394: ! 395: // ! 396: // remove the association between the address and the connection. ! 397: // ! 398: ! 399: TransportConnection->AddressFile = NULL; ! 400: ! 401: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2); ! 402: RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql); ! 403: ! 404: // ! 405: // and remove a reference to the address ! 406: // ! 407: ! 408: StDereferenceAddress ("Destroy association", addressFile->Address); ! 409: ! 410: ! 411: return STATUS_SUCCESS; ! 412: ! 413: } /* StDestroyAssociation */ ! 414: ! 415: ! 416: NTSTATUS ! 417: StIndicateDisconnect( ! 418: IN PTP_CONNECTION TransportConnection ! 419: ) ! 420: ! 421: /*++ ! 422: ! 423: Routine Description: ! 424: ! 425: This routine indicates a remote disconnection on this connection if it ! 426: is necessary to do so. No other action is taken here. ! 427: ! 428: This routine is only called by StDereferenceConnection. The reason for ! 429: this is that there may be multiple streams of execution which are ! 430: simultaneously referencing the same connection object, and it should ! 431: not be deleted out from under an interested stream of execution. ! 432: ! 433: Arguments: ! 434: ! 435: TransportConnection - Pointer to a transport connection structure to ! 436: be destroyed. ! 437: ! 438: Return Value: ! 439: ! 440: NTSTATUS - status of operation. ! 441: ! 442: --*/ ! 443: ! 444: { ! 445: PTP_ADDRESS_FILE addressFile; ! 446: PDEVICE_CONTEXT DeviceContext; ! 447: ULONG DisconnectReason; ! 448: PIRP DisconnectIrp; ! 449: KIRQL oldirql; ! 450: ! 451: ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql); ! 452: ! 453: if (((TransportConnection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) != 0)) { ! 454: ! 455: // ! 456: // Turn off all but the still-relevant bits in the flags. ! 457: // ! 458: ! 459: ASSERT (TransportConnection->Flags & CONNECTION_FLAGS_STOPPING); ! 460: ! 461: TransportConnection->Flags = CONNECTION_FLAGS_STOPPING; ! 462: TransportConnection->Flags2 &= ! 463: (CONNECTION_FLAGS2_ASSOCIATED | ! 464: CONNECTION_FLAGS2_DISASSOCIATED | ! 465: CONNECTION_FLAGS2_CLOSING); ! 466: ! 467: // ! 468: // Clean up other stuff -- basically everything gets ! 469: // done here except for the flags and the status, since ! 470: // they are used to block other requests. When the connection ! 471: // is given back to us (in Accept, Connect, or Listen) ! 472: // they are cleared. ! 473: // ! 474: ! 475: TransportConnection->MessageBytesReceived = (USHORT)0; // no data yet ! 476: TransportConnection->MessageBytesAcked = (USHORT)0; ! 477: ! 478: TransportConnection->CurrentReceiveRequest = (PTP_REQUEST)NULL; ! 479: ! 480: DisconnectIrp = TransportConnection->DisconnectIrp; ! 481: TransportConnection->DisconnectIrp = (PIRP)NULL; ! 482: ! 483: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql); ! 484: ! 485: ! 486: DeviceContext = TransportConnection->Provider; ! 487: addressFile = TransportConnection->AddressFile; ! 488: ! 489: ! 490: // ! 491: // If this connection was stopped by a call to TdiDisconnect, ! 492: // we have to complete that. We save the Irp so we can return ! 493: // the connection to the pool before we complete the request. ! 494: // ! 495: ! 496: ! 497: if (DisconnectIrp != (PIRP)NULL) { ! 498: ! 499: // ! 500: // Now complete the IRP if needed. This will be non-null ! 501: // only if TdiDisconnect was called, and we have not ! 502: // yet completed it. ! 503: // ! 504: ! 505: DisconnectIrp->IoStatus.Information = 0; ! 506: DisconnectIrp->IoStatus.Status = STATUS_SUCCESS; ! 507: IoCompleteRequest (DisconnectIrp, IO_NETWORK_INCREMENT); ! 508: ! 509: } else if ((TransportConnection->Status != STATUS_LOCAL_DISCONNECT) && ! 510: (addressFile->RegisteredDisconnectHandler == TRUE)) { ! 511: ! 512: // ! 513: // This was a remotely spawned disconnect, so indicate that ! 514: // to our client. Note that in the comparison above we ! 515: // check the status first, since if it is LOCAL_DISCONNECT ! 516: // addressFile may be NULL (BUGBUG: This is sort of a hack ! 517: // for PDK2, we should really indicate the disconnect inside ! 518: // StStopConnection, where we know addressFile is valid). ! 519: // ! 520: ! 521: // ! 522: // if the disconnection was remotely spawned, then indicate ! 523: // disconnect. In the case that a disconnect was issued at ! 524: // the same time as the connection went down remotely, we ! 525: // won't do this because DisconnectIrp will be non-NULL. ! 526: // ! 527: ! 528: // ! 529: // Invoke the user's disconnection event handler, if any. We do this here ! 530: // so that any outstanding sends will complete before we tear down the ! 531: // connection. ! 532: // ! 533: ! 534: DisconnectReason = 0; ! 535: if (TransportConnection->Flags & CONNECTION_FLAGS_ABORT) { ! 536: DisconnectReason |= TDI_DISCONNECT_ABORT; ! 537: } ! 538: if (TransportConnection->Flags & CONNECTION_FLAGS_DESTROY) { ! 539: DisconnectReason |= TDI_DISCONNECT_RELEASE; ! 540: } ! 541: ! 542: (*addressFile->DisconnectHandler)( ! 543: addressFile->DisconnectHandlerContext, ! 544: TransportConnection->Context, ! 545: 0, ! 546: NULL, ! 547: 0, ! 548: NULL, ! 549: DisconnectReason); ! 550: ! 551: } ! 552: ! 553: } else { ! 554: ! 555: // ! 556: // The client does not yet think that this connection ! 557: // is up...generally this happens due to request count ! 558: // fluctuation during connection setup. ! 559: // ! 560: ! 561: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql); ! 562: ! 563: } ! 564: ! 565: ! 566: return STATUS_SUCCESS; ! 567: ! 568: } /* StIndicateDisconnect */ ! 569: ! 570: ! 571: NTSTATUS ! 572: StDestroyConnection( ! 573: IN PTP_CONNECTION TransportConnection ! 574: ) ! 575: ! 576: /*++ ! 577: ! 578: Routine Description: ! 579: ! 580: This routine destroys a transport connection and removes all references ! 581: made by it to other objects in the transport. The connection structure ! 582: is returned to our lookaside list. It is assumed that the caller ! 583: has removed all IRPs from the connections's queues first. ! 584: ! 585: This routine is only called by StDereferenceConnection. The reason for ! 586: this is that there may be multiple streams of execution which are ! 587: simultaneously referencing the same connection object, and it should ! 588: not be deleted out from under an interested stream of execution. ! 589: ! 590: Arguments: ! 591: ! 592: TransportConnection - Pointer to a transport connection structure to ! 593: be destroyed. ! 594: ! 595: Return Value: ! 596: ! 597: NTSTATUS - status of operation. ! 598: ! 599: --*/ ! 600: ! 601: { ! 602: KIRQL oldirql; ! 603: PDEVICE_CONTEXT DeviceContext; ! 604: PIRP CloseIrp; ! 605: ! 606: ! 607: DeviceContext = TransportConnection->Provider; ! 608: ! 609: // ! 610: // Destroy any association that this connection has. ! 611: // ! 612: ! 613: StDestroyAssociation (TransportConnection); ! 614: ! 615: // ! 616: // Clear out any associated nasties hanging around the connection. Note ! 617: // that the current flags are set to STOPPING; this way anyone that may ! 618: // maliciously try to use the connection after it's dead and gone will ! 619: // just get ignored. ! 620: // ! 621: ! 622: TransportConnection->Flags = CONNECTION_FLAGS_STOPPING; ! 623: TransportConnection->Flags2 = CONNECTION_FLAGS2_CLOSING; ! 624: TransportConnection->MessageBytesReceived = (USHORT)0; // no data yet ! 625: TransportConnection->MessageBytesAcked = (USHORT)0; ! 626: ! 627: ! 628: // ! 629: // Now complete the close IRP. This will be set to non-null ! 630: // when CloseConnection was called. ! 631: // ! 632: ! 633: CloseIrp = TransportConnection->CloseIrp; ! 634: ! 635: if (CloseIrp != (PIRP)NULL) { ! 636: ! 637: TransportConnection->CloseIrp = (PIRP)NULL; ! 638: CloseIrp->IoStatus.Information = 0; ! 639: CloseIrp->IoStatus.Status = STATUS_SUCCESS; ! 640: IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT); ! 641: ! 642: } ! 643: ! 644: // ! 645: // Return the connection to the provider's pool. ! 646: // ! 647: ! 648: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql); ! 649: ! 650: DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse; ! 651: ++DeviceContext->ConnectionSamples; ! 652: --DeviceContext->ConnectionInUse; ! 653: ! 654: if ((DeviceContext->ConnectionAllocated - DeviceContext->ConnectionInUse) > ! 655: DeviceContext->ConnectionInitAllocated) { ! 656: StDeallocateConnection (DeviceContext, TransportConnection); ! 657: } else { ! 658: InsertTailList (&DeviceContext->ConnectionPool, &TransportConnection->LinkList); ! 659: } ! 660: ! 661: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); ! 662: ! 663: StDereferenceDeviceContext ("Destroy Connection", DeviceContext); ! 664: ! 665: return STATUS_SUCCESS; ! 666: ! 667: } /* StDestroyConnection */ ! 668: ! 669: ! 670: VOID ! 671: StRefConnection( ! 672: IN PTP_CONNECTION TransportConnection ! 673: ) ! 674: ! 675: /*++ ! 676: ! 677: Routine Description: ! 678: ! 679: This routine increments the reference count on a transport connection. ! 680: ! 681: Arguments: ! 682: ! 683: TransportConnection - Pointer to a transport connection object. ! 684: ! 685: Return Value: ! 686: ! 687: none. ! 688: ! 689: --*/ ! 690: ! 691: { ! 692: INTERLOCKED_RESULT result; ! 693: ! 694: result = ExInterlockedIncrementLong ( ! 695: &TransportConnection->ReferenceCount, ! 696: TransportConnection->ProviderInterlock); ! 697: ! 698: if (result == ResultZero) { ! 699: ! 700: // ! 701: // The first increment causes us to increment the ! 702: // "ref count is not zero" special ref. ! 703: // ! 704: ! 705: ExInterlockedAddUlong( ! 706: (PULONG)(&TransportConnection->SpecialRefCount), ! 707: 1, ! 708: TransportConnection->ProviderInterlock); ! 709: ! 710: } ! 711: ! 712: ASSERT (result != ResultNegative); ! 713: ! 714: } /* StRefConnection */ ! 715: ! 716: ! 717: VOID ! 718: StDerefConnection( ! 719: IN PTP_CONNECTION TransportConnection ! 720: ) ! 721: ! 722: /*++ ! 723: ! 724: Routine Description: ! 725: ! 726: This routine dereferences a transport connection by decrementing the ! 727: reference count contained in the structure. If, after being ! 728: decremented, the reference count is zero, then this routine calls ! 729: StDestroyConnection to remove it from the system. ! 730: ! 731: Arguments: ! 732: ! 733: TransportConnection - Pointer to a transport connection object. ! 734: ! 735: Return Value: ! 736: ! 737: none. ! 738: ! 739: --*/ ! 740: ! 741: { ! 742: INTERLOCKED_RESULT result; ! 743: ! 744: result = ExInterlockedDecrementLong ( ! 745: &TransportConnection->ReferenceCount, ! 746: TransportConnection->ProviderInterlock); ! 747: ! 748: // ! 749: // If all the normal references to this connection are gone, then ! 750: // we can remove the special reference that stood for ! 751: // "the regular ref count is non-zero". ! 752: // ! 753: ! 754: if (result == ResultNegative) { ! 755: ! 756: // ! 757: // If the refcount is -1, then we need to indicate ! 758: // disconnect. However, we need to ! 759: // do this before we actually do the special deref, since ! 760: // otherwise the connection might go away while we ! 761: // are doing that. ! 762: // ! 763: ! 764: StIndicateDisconnect (TransportConnection); ! 765: ! 766: // ! 767: // Now it is OK to let the connection go away. ! 768: // ! 769: ! 770: StDereferenceConnectionSpecial ("Regular ref gone", TransportConnection); ! 771: ! 772: } ! 773: ! 774: } /* StDerefConnection */ ! 775: ! 776: ! 777: VOID ! 778: StDerefConnectionSpecial( ! 779: IN PTP_CONNECTION TransportConnection ! 780: ) ! 781: ! 782: /*++ ! 783: ! 784: Routine Description: ! 785: ! 786: This routines completes the dereferencing of a connection. ! 787: It may be called any time, but it does not do its work until ! 788: the regular reference count is also 0. ! 789: ! 790: Arguments: ! 791: ! 792: TransportConnection - Pointer to a transport connection object. ! 793: ! 794: Return Value: ! 795: ! 796: none. ! 797: ! 798: --*/ ! 799: ! 800: { ! 801: KIRQL oldirql; ! 802: ! 803: ACQUIRE_SPIN_LOCK (TransportConnection->ProviderInterlock, &oldirql); ! 804: ! 805: --TransportConnection->SpecialRefCount; ! 806: ! 807: if ((TransportConnection->SpecialRefCount == 0) && ! 808: (TransportConnection->ReferenceCount == -1)) { ! 809: ! 810: // ! 811: // If we have deleted all references to this connection, then we can ! 812: // destroy the object. It is okay to have already released the spin ! 813: // lock at this point because there is no possible way that another ! 814: // stream of execution has access to the connection any longer. ! 815: // ! 816: ! 817: RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql); ! 818: ! 819: StDestroyConnection (TransportConnection); ! 820: ! 821: } else { ! 822: ! 823: RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql); ! 824: ! 825: } ! 826: ! 827: } /* StDerefConnectionSpecial */ ! 828: ! 829: ! 830: PTP_CONNECTION ! 831: StFindConnection( ! 832: IN PDEVICE_CONTEXT DeviceContext, ! 833: IN PUCHAR LocalName, ! 834: IN PUCHAR RemoteName ! 835: ) ! 836: ! 837: /*++ ! 838: ! 839: Routine Description: ! 840: ! 841: This routine scans the connections associated with a ! 842: device context, and determines if there is an connection ! 843: associated with the specific remote address on the ! 844: specific local address. ! 845: ! 846: Arguments: ! 847: ! 848: DeviceContext - Pointer to the device context. ! 849: ! 850: LocalName - The 16-character Netbios name of the local address. ! 851: ! 852: RemoteName - The 16-character Netbios name of the remote. ! 853: ! 854: Return Value: ! 855: ! 856: The connection if one is found, NULL otherwise. ! 857: ! 858: --*/ ! 859: ! 860: { ! 861: KIRQL oldirql; ! 862: PLIST_ENTRY Flink; ! 863: PTP_ADDRESS Address; ! 864: BOOLEAN MatchedAddress = FALSE; ! 865: PTP_CONNECTION Connection; ! 866: ! 867: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql); ! 868: ! 869: for (Flink = DeviceContext->AddressDatabase.Flink; ! 870: Flink != &DeviceContext->AddressDatabase; ! 871: Flink = Flink->Flink) { ! 872: ! 873: Address = CONTAINING_RECORD ( ! 874: Flink, ! 875: TP_ADDRESS, ! 876: Linkage); ! 877: ! 878: if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) { ! 879: continue; ! 880: } ! 881: ! 882: if (StMatchNetbiosAddress (Address, LocalName)) { ! 883: ! 884: StReferenceAddress ("Looking for connection", Address); // prevent address from being destroyed. ! 885: MatchedAddress = TRUE; ! 886: break; ! 887: ! 888: } ! 889: } ! 890: ! 891: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); ! 892: ! 893: if (!MatchedAddress) { ! 894: return NULL; ! 895: } ! 896: ! 897: Connection = StLookupRemoteName (Address, RemoteName); ! 898: ! 899: StDereferenceAddress ("Looking for connection", Address); ! 900: ! 901: return Connection; ! 902: ! 903: } ! 904: ! 905: ! 906: PTP_CONNECTION ! 907: StLookupConnectionByContext( ! 908: IN PTP_ADDRESS Address, ! 909: IN CONNECTION_CONTEXT ConnectionContext ! 910: ) ! 911: ! 912: /*++ ! 913: ! 914: Routine Description: ! 915: ! 916: This routine accepts a connection identifier and an address and ! 917: returns a pointer to the connection object, TP_CONNECTION. If the ! 918: connection identifier is not found on the address, then NULL is returned. ! 919: This routine automatically increments the reference count of the ! 920: TP_CONNECTION structure if it is found. It is assumed that the ! 921: TP_ADDRESS structure is already held with a reference count. ! 922: ! 923: BUGBUG: Should the ConnectionDatabase go in the address file? ! 924: ! 925: Arguments: ! 926: ! 927: Address - Pointer to a transport address object. ! 928: ! 929: ConnectionContext - Connection Context for this address. ! 930: ! 931: Return Value: ! 932: ! 933: A pointer to the connection we found ! 934: ! 935: --*/ ! 936: ! 937: { ! 938: KIRQL oldirql, oldirql1; ! 939: PLIST_ENTRY p; ! 940: PTP_CONNECTION Connection; ! 941: ! 942: // ! 943: // Currently, this implementation is inefficient, but brute force so ! 944: // that a system can get up and running. Later, a cache of the mappings ! 945: // of popular connection id's and pointers to their TP_CONNECTION structures ! 946: // will be searched first. ! 947: // ! 948: ! 949: ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); ! 950: ! 951: for (p=Address->ConnectionDatabase.Flink; ! 952: p != &Address->ConnectionDatabase; ! 953: p=p->Flink) { ! 954: ! 955: ! 956: Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList); ! 957: ! 958: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1); ! 959: ! 960: if ((Connection->Context == ConnectionContext) && ! 961: ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0)) { ! 962: // This reference is removed by the calling function ! 963: StReferenceConnection ("Lookup up for request", Connection); ! 964: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1); ! 965: RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); ! 966: ! 967: return Connection; ! 968: } ! 969: ! 970: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1); ! 971: ! 972: } ! 973: ! 974: RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); ! 975: ! 976: return NULL; ! 977: ! 978: } /* StLookupConnectionByContext */ ! 979: ! 980: ! 981: PTP_CONNECTION ! 982: StLookupListeningConnection( ! 983: IN PTP_ADDRESS Address ! 984: ) ! 985: ! 986: /*++ ! 987: ! 988: Routine Description: ! 989: ! 990: This routine scans the connection database on an address to find ! 991: a TP_CONNECTION object which has CONNECTION_FLAGS_WAIT_NQ ! 992: flag set. It returns a pointer to the found connection object (and ! 993: simultaneously resets the flag) or NULL if it could not be found. ! 994: The reference count is also incremented atomically on the connection. ! 995: ! 996: Arguments: ! 997: ! 998: Address - Pointer to a transport address object. ! 999: ! 1000: Return Value: ! 1001: ! 1002: NTSTATUS - status of operation. ! 1003: ! 1004: --*/ ! 1005: ! 1006: { ! 1007: KIRQL oldirql, oldirql1; ! 1008: PTP_CONNECTION Connection; ! 1009: PLIST_ENTRY p; ! 1010: ! 1011: ! 1012: ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); ! 1013: ! 1014: for (p=Address->ConnectionDatabase.Flink; ! 1015: p != &Address->ConnectionDatabase; ! 1016: p=p->Flink) { ! 1017: ! 1018: ! 1019: Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList); ! 1020: if (Connection->Flags & CONNECTION_FLAGS_WAIT_LISTEN) { ! 1021: ! 1022: // This reference is removed by the calling function ! 1023: StReferenceConnection ("Found Listening", Connection); ! 1024: ! 1025: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1); ! 1026: Connection->Flags &= ~CONNECTION_FLAGS_WAIT_LISTEN; ! 1027: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1); ! 1028: RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); ! 1029: ! 1030: return Connection; ! 1031: } ! 1032: ! 1033: } ! 1034: ! 1035: RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); ! 1036: ! 1037: return NULL; ! 1038: ! 1039: } /* StLookupListeningConnection */ ! 1040: ! 1041: ! 1042: VOID ! 1043: StStopConnection( ! 1044: IN PTP_CONNECTION Connection, ! 1045: IN NTSTATUS Status ! 1046: ) ! 1047: ! 1048: /*++ ! 1049: ! 1050: Routine Description: ! 1051: ! 1052: This routine is called to terminate all activity on a connection and ! 1053: destroy the object. This is done in a graceful manner; i.e., all ! 1054: outstanding requests are terminated by cancelling them, etc. It is ! 1055: assumed that the caller has a reference to this connection object, ! 1056: but this routine will do the dereference for the one issued at creation ! 1057: time. ! 1058: ! 1059: Orderly release is a function of this routine, but it is not a provided ! 1060: service of this transport provider, so there is no code to do it here. ! 1061: ! 1062: Arguments: ! 1063: ! 1064: Connection - Pointer to a TP_CONNECTION object. ! 1065: ! 1066: Status - The status that caused us to stop the connection. This ! 1067: will determine what status pending requests are aborted with, ! 1068: and also how we proceed during the stop (whether to send a ! 1069: session end, and whether to indicate disconnect). ! 1070: ! 1071: Return Value: ! 1072: ! 1073: none. ! 1074: ! 1075: --*/ ! 1076: ! 1077: { ! 1078: KIRQL oldirql, oldirql1, cancelirql; ! 1079: PLIST_ENTRY p; ! 1080: PIRP Irp; ! 1081: PTP_REQUEST Request; ! 1082: ULONG DisconnectReason; ! 1083: PULONG StopCounter; ! 1084: PDEVICE_CONTEXT DeviceContext; ! 1085: BOOLEAN WasConnected; ! 1086: ! 1087: ! 1088: DeviceContext = Connection->Provider; ! 1089: ! 1090: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 1091: if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING)) { ! 1092: ! 1093: // ! 1094: // We are stopping the connection, record statistics ! 1095: // about it. ! 1096: // ! 1097: ! 1098: if (Connection->Flags & CONNECTION_FLAGS_READY) { ! 1099: ! 1100: DECREMENT_COUNTER (DeviceContext, OpenConnections); ! 1101: WasConnected = TRUE; ! 1102: ! 1103: } else { ! 1104: ! 1105: WasConnected = FALSE; ! 1106: ! 1107: } ! 1108: ! 1109: Connection->Flags &= ~CONNECTION_FLAGS_READY; // no longer open for business ! 1110: Connection->Flags |= CONNECTION_FLAGS_STOPPING; ! 1111: Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID; ! 1112: Connection->SendState = CONNECTION_SENDSTATE_IDLE; ! 1113: Connection->Status = Status; ! 1114: ! 1115: // ! 1116: // If this connection is waiting to packetize, ! 1117: // remove it from the device context queue it is on. ! 1118: // ! 1119: // NOTE: If the connection is currently in the ! 1120: // packetize queue, it will eventually go to get ! 1121: // packetized and at that point it will get ! 1122: // removed. ! 1123: // ! 1124: ! 1125: if (Connection->Flags & CONNECTION_FLAGS_SUSPENDED) { ! 1126: ! 1127: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1); ! 1128: RemoveEntryList (&Connection->PacketWaitLinkage); ! 1129: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1); ! 1130: } ! 1131: ! 1132: ! 1133: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1134: ! 1135: IoAcquireCancelSpinLock(&cancelirql); ! 1136: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 1137: ! 1138: ! 1139: // ! 1140: // Run down all TdiSend requests on this connection. ! 1141: // ! 1142: ! 1143: while (TRUE) { ! 1144: p = RemoveHeadList (&Connection->SendQueue); ! 1145: if (p == &Connection->SendQueue) { ! 1146: break; ! 1147: } ! 1148: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1149: Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry); ! 1150: Irp->CancelRoutine = (PDRIVER_CANCEL)NULL; ! 1151: IoReleaseCancelSpinLock(cancelirql); ! 1152: StCompleteSendIrp (Irp, Connection->Status, 0); ! 1153: IoAcquireCancelSpinLock(&cancelirql); ! 1154: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 1155: } ! 1156: ! 1157: // ! 1158: // NOTE: We hold the connection spinlock AND the ! 1159: // cancel spinlock here. ! 1160: // ! 1161: ! 1162: Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE; ! 1163: ! 1164: // ! 1165: // Run down all TdiReceive requests on this connection. ! 1166: // ! 1167: ! 1168: while (TRUE) { ! 1169: p = RemoveHeadList (&Connection->ReceiveQueue); ! 1170: if (p == &Connection->ReceiveQueue) { ! 1171: break; ! 1172: } ! 1173: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1174: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); ! 1175: Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL; ! 1176: IoReleaseCancelSpinLock(cancelirql); ! 1177: ! 1178: StCompleteRequest (Request, Connection->Status, 0); ! 1179: IoAcquireCancelSpinLock(&cancelirql); ! 1180: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 1181: } ! 1182: ! 1183: ! 1184: // ! 1185: // NOTE: We hold the connection spinlock AND the ! 1186: // cancel spinlock here. ! 1187: // ! 1188: ! 1189: // ! 1190: // Run down all TdiConnect/TdiDisconnect/TdiListen requests. ! 1191: // ! 1192: ! 1193: while (TRUE) { ! 1194: p = RemoveHeadList (&Connection->InProgressRequest); ! 1195: if (p == &Connection->InProgressRequest) { ! 1196: break; ! 1197: } ! 1198: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1199: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); ! 1200: Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL; ! 1201: IoReleaseCancelSpinLock(cancelirql); ! 1202: ! 1203: StCompleteRequest (Request, Connection->Status, 0); ! 1204: ! 1205: IoAcquireCancelSpinLock(&cancelirql); ! 1206: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 1207: } ! 1208: ! 1209: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1210: IoReleaseCancelSpinLock(cancelirql); ! 1211: ! 1212: // ! 1213: // If we aren't DESTROYing the link, then send a SESSION_END frame ! 1214: // to the remote side. When the SESSION_END frame is acknowleged, ! 1215: // we will decrement the connection's reference count by one, removing ! 1216: // its creation reference. This will cause the connection object to ! 1217: // be disposed of, and will begin running down the link. ! 1218: // DGB: add logic to avoid blowing away link if one doesn't exist yet. ! 1219: // ! 1220: ! 1221: DisconnectReason = 0; ! 1222: if (Connection->Flags & CONNECTION_FLAGS_ABORT) { ! 1223: DisconnectReason |= TDI_DISCONNECT_ABORT; ! 1224: } ! 1225: if (Connection->Flags & CONNECTION_FLAGS_DESTROY) { ! 1226: DisconnectReason |= TDI_DISCONNECT_RELEASE; ! 1227: } ! 1228: ! 1229: // ! 1230: // When this completes we will dereference the connection. ! 1231: // ! 1232: ! 1233: if (WasConnected) { ! 1234: StSendDisconnect (Connection); ! 1235: } ! 1236: ! 1237: ! 1238: switch (Status) { ! 1239: ! 1240: case STATUS_LOCAL_DISCONNECT: ! 1241: StopCounter = &DeviceContext->LocalDisconnects; ! 1242: break; ! 1243: case STATUS_REMOTE_DISCONNECT: ! 1244: StopCounter = &DeviceContext->RemoteDisconnects; ! 1245: break; ! 1246: case STATUS_LINK_FAILED: ! 1247: StopCounter = &DeviceContext->LinkFailures; ! 1248: break; ! 1249: case STATUS_IO_TIMEOUT: ! 1250: StopCounter = &DeviceContext->SessionTimeouts; ! 1251: break; ! 1252: case STATUS_CANCELLED: ! 1253: StopCounter = &DeviceContext->CancelledConnections; ! 1254: break; ! 1255: case STATUS_REMOTE_RESOURCES: ! 1256: StopCounter = &DeviceContext->RemoteResourceFailures; ! 1257: break; ! 1258: case STATUS_INSUFFICIENT_RESOURCES: ! 1259: StopCounter = &DeviceContext->LocalResourceFailures; ! 1260: break; ! 1261: case STATUS_BAD_NETWORK_PATH: ! 1262: StopCounter = &DeviceContext->NotFoundFailures; ! 1263: break; ! 1264: case STATUS_REMOTE_NOT_LISTENING: ! 1265: StopCounter = &DeviceContext->NoListenFailures; ! 1266: break; ! 1267: ! 1268: default: ! 1269: StopCounter = NULL; ! 1270: break; ! 1271: ! 1272: } ! 1273: ! 1274: if (StopCounter != NULL) { ! 1275: ! 1276: ExInterlockedIncrementLong( ! 1277: (PLONG)StopCounter, ! 1278: &DeviceContext->StatisticsInterlock); ! 1279: ! 1280: } ! 1281: ! 1282: ! 1283: // ! 1284: // Note that we've blocked all new requests being queued during the ! 1285: // time we have been in this teardown code; StDestroyConnection also ! 1286: // sets the connection flags to STOPPING when returning the ! 1287: // connection to the queue. This avoids lingerers using non-existent ! 1288: // connections. ! 1289: // ! 1290: ! 1291: } else { ! 1292: ! 1293: // ! 1294: // The connection was already stopping. ! 1295: // ! 1296: ! 1297: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1298: ! 1299: } ! 1300: ! 1301: } /* StStopConnection */ ! 1302: ! 1303: ! 1304: VOID ! 1305: StCancelConnection( ! 1306: IN PDEVICE_OBJECT DeviceObject, ! 1307: IN PIRP Irp ! 1308: ) ! 1309: ! 1310: /*++ ! 1311: ! 1312: Routine Description: ! 1313: ! 1314: This routine is called by the I/O system to cancel a connect ! 1315: or a listen. It is simple since there can only be one of these ! 1316: active on a connection; we just stop the connection, the IRP ! 1317: will get completed as part of normal session teardown. ! 1318: ! 1319: NOTE: This routine is called with the CancelSpinLock held and ! 1320: is responsible for releasing it. ! 1321: ! 1322: Arguments: ! 1323: ! 1324: DeviceObject - Pointer to the device object for this driver. ! 1325: ! 1326: Irp - Pointer to the request packet representing the I/O request. ! 1327: ! 1328: Return Value: ! 1329: ! 1330: none. ! 1331: ! 1332: --*/ ! 1333: ! 1334: { ! 1335: KIRQL oldirql; ! 1336: PIO_STACK_LOCATION IrpSp; ! 1337: PTP_CONNECTION Connection; ! 1338: PTP_REQUEST Request; ! 1339: PLIST_ENTRY p; ! 1340: ! 1341: UNREFERENCED_PARAMETER (DeviceObject); ! 1342: ! 1343: // ! 1344: // Get a pointer to the current stack location in the IRP. This is where ! 1345: // the function codes and parameters are stored. ! 1346: // ! 1347: ! 1348: IrpSp = IoGetCurrentIrpStackLocation (Irp); ! 1349: ! 1350: ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) && ! 1351: (IrpSp->MinorFunction == TDI_CONNECT || IrpSp->MinorFunction == TDI_LISTEN)); ! 1352: ! 1353: Connection = IrpSp->FileObject->FsContext; ! 1354: ! 1355: // ! 1356: // Since this IRP is still in the cancellable state, we know ! 1357: // that the connection is still around (although it may be in ! 1358: // the process of being torn down). ! 1359: // ! 1360: ! 1361: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 1362: StReferenceConnection ("Cancelling Send", Connection); ! 1363: ! 1364: p = RemoveHeadList (&Connection->InProgressRequest); ! 1365: ASSERT (p != &Connection->InProgressRequest); ! 1366: ! 1367: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1368: ! 1369: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); ! 1370: ASSERT (Request->IoRequestPacket == Irp); ! 1371: Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL; ! 1372: ! 1373: IoReleaseCancelSpinLock(Irp->CancelIrql); ! 1374: ! 1375: StCompleteRequest (Request, STATUS_CANCELLED, 0); ! 1376: StStopConnection (Connection, STATUS_CANCELLED); ! 1377: ! 1378: StDereferenceConnection ("Cancel done", Connection); ! 1379: ! 1380: } ! 1381:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.