|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1989-1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: sendeng.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains code that implements the send engine for the ! 12: Sample transport provider. ! 13: ! 14: Environment: ! 15: ! 16: Kernel mode ! 17: ! 18: Revision History: ! 19: ! 20: ! 21: --*/ ! 22: ! 23: #include "st.h" ! 24: #if 27 ! 25: ULONG StNoisySend = 0; ! 26: ULONG StSndLoc = 0; ! 27: ULONG StSnds[10]; ! 28: #endif ! 29: ! 30: ! 31: VOID ! 32: StartPacketizingConnection( ! 33: PTP_CONNECTION Connection, ! 34: IN BOOLEAN Immediate, ! 35: IN KIRQL ConnectionIrql, ! 36: IN KIRQL CancelIrql ! 37: ) ! 38: ! 39: /*++ ! 40: ! 41: Routine Description: ! 42: ! 43: This routine is called to place a connection on the PacketizeQueue ! 44: of its device context object. Then this routine starts packetizing ! 45: the first connection on that queue. ! 46: ! 47: *** The Connection spin lock must be held on entry to this routine. ! 48: Optionally, the cancel spin lock may be held. If so, the cancel ! 49: spin lock must have been acquired first. ! 50: ! 51: Arguments: ! 52: ! 53: Connection - Pointer to a TP_CONNECTION object. ! 54: ! 55: Immediate - TRUE if the connection should be packetized ! 56: immediately; FALSE if the connection should be queued ! 57: up for later packetizing (implies that ReceiveComplete ! 58: will be called in the future, which packetizes always). ! 59: ! 60: NOTE: If this is TRUE, it also implies that we have ! 61: a connection reference. ! 62: ! 63: ConnectionIrql - The OldIrql value when the connection spin lock ! 64: was acquired. ! 65: ! 66: CancelIrql - The OldIrql value when the cancel spin lock was ! 67: acquired. -1 means that the cancel spin lock isn't held. ! 68: ! 69: Return Value: ! 70: ! 71: none. ! 72: ! 73: --*/ ! 74: ! 75: { ! 76: PDEVICE_CONTEXT DeviceContext; ! 77: ! 78: DeviceContext = Connection->Provider; ! 79: ! 80: // ! 81: // If this connection's SendState is set to PACKETIZE and if ! 82: // we are not already on the PacketizeQueue, then go ahead and ! 83: // append us to the end of that queue, and remember that we're ! 84: // on it by setting the CONNECTION_FLAGS_PACKETIZE bitflag. ! 85: // ! 86: // Also don't queue it if the connection is stopping. ! 87: // ! 88: ! 89: if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) && ! 90: !(Connection->Flags & ! 91: (CONNECTION_FLAGS_PACKETIZE | CONNECTION_FLAGS_STOPPING))) { ! 92: ! 93: Connection->Flags |= CONNECTION_FLAGS_PACKETIZE; ! 94: ! 95: if (!Immediate) { ! 96: StReferenceConnection ("Packetize", Connection); ! 97: } ! 98: ! 99: ExInterlockedInsertTailList( ! 100: &DeviceContext->PacketizeQueue, ! 101: &Connection->PacketizeLinkage, ! 102: &DeviceContext->SpinLock); ! 103: ! 104: RELEASE_SPIN_LOCK (&Connection->SpinLock, ConnectionIrql); ! 105: ! 106: } else { ! 107: ! 108: RELEASE_SPIN_LOCK (&Connection->SpinLock, ConnectionIrql); ! 109: if (Immediate) { ! 110: StDereferenceConnection("temp TdiSend", Connection); ! 111: } ! 112: } ! 113: ! 114: if (CancelIrql != (KIRQL)-1) { ! 115: IoReleaseCancelSpinLock (CancelIrql); ! 116: } ! 117: ! 118: if (Immediate) { ! 119: PacketizeConnections (DeviceContext); ! 120: } ! 121: ! 122: } /* StartPacketizingConnection */ ! 123: ! 124: ! 125: VOID ! 126: PacketizeConnections( ! 127: PDEVICE_CONTEXT DeviceContext ! 128: ) ! 129: ! 130: /*++ ! 131: ! 132: Routine Description: ! 133: ! 134: This routine attempts to packetize all connections waiting on the ! 135: PacketizeQueue of the DeviceContext. ! 136: ! 137: ! 138: Arguments: ! 139: ! 140: DeviceContext - Pointer to a DEVICE_CONTEXT object. ! 141: ! 142: Return Value: ! 143: ! 144: none. ! 145: ! 146: --*/ ! 147: ! 148: { ! 149: PLIST_ENTRY p; ! 150: PTP_CONNECTION Connection; ! 151: ! 152: // ! 153: // Pick connections off of the device context's packetization queue ! 154: // until there are no more left to pick off. For each one, we call ! 155: // PacketizeSend. Note this routine can be executed concurrently ! 156: // on multiple processors and it doesn't matter; multiple connections ! 157: // may be packetized concurrently. ! 158: // ! 159: ! 160: while (TRUE) { ! 161: ! 162: p = ExInterlockedRemoveHeadList( ! 163: &DeviceContext->PacketizeQueue, ! 164: &DeviceContext->SpinLock); ! 165: ! 166: if (p == NULL) { ! 167: break; ! 168: } ! 169: Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage); ! 170: PacketizeSend (Connection); ! 171: } ! 172: ! 173: } /* PacketizeConnections */ ! 174: ! 175: ! 176: VOID ! 177: PacketizeSend( ! 178: PTP_CONNECTION Connection ! 179: ) ! 180: ! 181: /*++ ! 182: ! 183: Routine Description: ! 184: ! 185: This routine packetizes the current TdiSend request on the specified ! 186: connection as much as limits will permit. A given here is that there ! 187: is an active send on the connection that needs further packetization. ! 188: ! 189: Arguments: ! 190: ! 191: Connection - Pointer to a TP_CONNECTION object. ! 192: ! 193: Return Value: ! 194: ! 195: none. ! 196: ! 197: --*/ ! 198: ! 199: { ! 200: KIRQL oldirql, oldirql1; ! 201: ULONG MaxFrameSize, FrameSize; ! 202: ULONG PacketBytes; ! 203: TP_SEND_POINTER SavedSendPointer; ! 204: PNDIS_BUFFER PacketDescriptor; ! 205: PUCHAR SourceRouting; ! 206: UINT SourceRoutingLength; ! 207: PDEVICE_CONTEXT DeviceContext; ! 208: PTP_PACKET Packet; ! 209: NTSTATUS Status; ! 210: PST_HEADER StHeader; ! 211: UINT HeaderLength; ! 212: PIO_STACK_LOCATION IrpSp; ! 213: PSEND_PACKET_TAG SendTag; ! 214: ULONG LastPacketLength; ! 215: ! 216: DeviceContext = Connection->Provider; ! 217: ! 218: // ! 219: // Just loop until one of three events happens: (1) we run out of ! 220: // packets from StCreatePacket, (2) we completely packetize the send. ! 221: // ! 222: ! 223: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 224: ! 225: if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) { ! 226: Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE; ! 227: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 228: StDereferenceConnection ("No longer packetizing", Connection); ! 229: return; ! 230: } ! 231: ! 232: MaxFrameSize = Connection->MaximumDataSize; ! 233: ! 234: // ! 235: // It is possible for a frame to arrive during the middle of this loop ! 236: // (such as a NO_RECEIVE) that will put us into a new state (such as ! 237: // W_RCVCONT). For this reason, we have to check the state every time ! 238: // (at the end of the loop). ! 239: // ! 240: ! 241: do { ! 242: ! 243: if (!NT_SUCCESS (StCreatePacket (DeviceContext, &Packet))) { ! 244: ! 245: // ! 246: // We need a packet to finish packetizing the current send, but ! 247: // there are no more packets available in the pool right now. ! 248: // Set our send state to W_PACKET, and put this connection on ! 249: // the PacketWaitQueue of the device context object. Then, ! 250: // when StDestroyPacket frees up a packet, it will check this ! 251: // queue for starved connections, and if it finds one, it will ! 252: // take a connection off the list and set its send state to ! 253: // SENDSTATE_PACKETIZE and put it on the PacketizeQueue. ! 254: // ! 255: ! 256: Connection->SendState = CONNECTION_SENDSTATE_W_PACKET; ! 257: ! 258: // ! 259: // Clear the PACKETIZE flag, indicating that we're no longer ! 260: // on the PacketizeQueue or actively packetizing. The flag ! 261: // was set by StartPacketizingConnection to indicate that ! 262: // the connection was already on the PacketizeQueue. ! 263: // ! 264: // Don't queue him if the connection is stopping. ! 265: // ! 266: ! 267: Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE; ! 268: ! 269: if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING)) { ! 270: Connection->Flags |= CONNECTION_FLAGS_SUSPENDED; ! 271: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1); ! 272: InsertTailList (&DeviceContext->PacketWaitQueue, &Connection->PacketWaitLinkage); ! 273: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1); ! 274: } ! 275: ! 276: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 277: StDereferenceConnection ("No packet", Connection); ! 278: return; ! 279: ! 280: } ! 281: ! 282: // ! 283: // Add a reference count to the IRP, and keep track of ! 284: // which request it is. Send completion will remove the ! 285: // reference. ! 286: ! 287: IrpSp = IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp); ! 288: ! 289: SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved); ! 290: SendTag->Type = TYPE_I_FRAME; ! 291: SendTag->Packet = Packet; ! 292: SendTag->Owner = (PVOID)IrpSp; ! 293: ! 294: Packet->CompleteSend = FALSE; ! 295: ! 296: ! 297: // ! 298: // Build the MAC header. All frames go out as ! 299: // single-route source routing. ! 300: // ! 301: ! 302: ! 303: MacReturnSingleRouteSR( ! 304: &DeviceContext->MacInfo, ! 305: &SourceRouting, ! 306: &SourceRoutingLength); ! 307: ! 308: MacConstructHeader ( ! 309: &DeviceContext->MacInfo, ! 310: Packet->Header, ! 311: DeviceContext->MulticastAddress.Address, ! 312: DeviceContext->LocalAddress.Address, ! 313: sizeof(ST_HEADER), ! 314: SourceRouting, ! 315: SourceRoutingLength, ! 316: &HeaderLength); ! 317: ! 318: // ! 319: // Build the header: 'I', dest, source ! 320: // ! 321: ! 322: StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]); ! 323: ! 324: StHeader->Signature = ST_SIGNATURE; ! 325: StHeader->Command = ST_CMD_INFORMATION; ! 326: StHeader->Flags = 0; ! 327: ! 328: RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16); ! 329: RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16); ! 330: ! 331: HeaderLength += sizeof(ST_HEADER); ! 332: ! 333: ! 334: // ! 335: // Modify the packet length and send the it. ! 336: // ! 337: ! 338: StSetNdisPacketLength(Packet->NdisPacket, HeaderLength); ! 339: ! 340: StReferenceSendIrp ("Packetize", IrpSp); ! 341: ! 342: // ! 343: // Save our complex send pointer in case we have to restore it ! 344: // because StNdisSend fails. ! 345: // ! 346: ! 347: SavedSendPointer = Connection->sp; ! 348: ! 349: // ! 350: // build an NDIS_BUFFER chain that describes the buffer we're using, and ! 351: // thread it off the NdisBuffer. This chain may not complete the ! 352: // packet, as the remaining part of the MDL chain may be shorter than ! 353: // the packet. ! 354: // ! 355: ! 356: FrameSize = MaxFrameSize; ! 357: ! 358: // ! 359: // Check if we have less than FrameSize left to send. ! 360: // ! 361: ! 362: if (Connection->sp.MessageBytesSent + FrameSize > Connection->CurrentSendLength) { ! 363: ! 364: FrameSize = Connection->CurrentSendLength - Connection->sp.MessageBytesSent; ! 365: ! 366: } ! 367: #if 27 ! 368: if (StNoisySend) { ! 369: DbgPrint ("Send %d of %d\n", FrameSize, Connection->CurrentSendLength); ! 370: } ! 371: if (FrameSize > 1000) { ! 372: StSnds[StSndLoc] = FrameSize; ! 373: StSndLoc = (StSndLoc + 1) % 10; ! 374: } ! 375: #endif ! 376: ! 377: ! 378: // ! 379: // Make a copy of the MDL chain for this send, unless ! 380: // there are zero bytes left. ! 381: // ! 382: ! 383: if (FrameSize != 0) { ! 384: ! 385: // ! 386: // If the whole send will fit inside one packet, ! 387: // then there is no need to duplicate the MDL ! 388: // (note that this may include multi-MDL sends). ! 389: // ! 390: ! 391: if ((Connection->sp.SendByteOffset == 0) && ! 392: (Connection->CurrentSendLength == FrameSize)) { ! 393: ! 394: PacketDescriptor = (PNDIS_BUFFER)Connection->sp.CurrentSendMdl; ! 395: PacketBytes = FrameSize; ! 396: Connection->sp.CurrentSendMdl = NULL; ! 397: Connection->sp.SendByteOffset = FrameSize; ! 398: Packet->PacketNoNdisBuffer = TRUE; ! 399: Status = STATUS_SUCCESS; ! 400: ! 401: } else { ! 402: ! 403: Status = BuildBufferChainFromMdlChain ( ! 404: DeviceContext->NdisBufferPoolHandle, ! 405: Connection->sp.CurrentSendMdl, ! 406: Connection->sp.SendByteOffset, ! 407: FrameSize, ! 408: &PacketDescriptor, ! 409: &Connection->sp.CurrentSendMdl, ! 410: &Connection->sp.SendByteOffset, ! 411: &PacketBytes); ! 412: ! 413: } ! 414: ! 415: } else { ! 416: ! 417: PacketBytes = 0; ! 418: Connection->sp.CurrentSendMdl = NULL; ! 419: Status = STATUS_SUCCESS; ! 420: ! 421: } ! 422: ! 423: if (NT_SUCCESS (Status)) { ! 424: ! 425: Connection->sp.MessageBytesSent += PacketBytes; ! 426: ! 427: // ! 428: // Chain the buffers to the packet, unless there ! 429: // are zero bytes of data. ! 430: // ! 431: ! 432: if (FrameSize != 0) { ! 433: NdisChainBufferAtBack (Packet->NdisPacket, PacketDescriptor); ! 434: } ! 435: ! 436: ! 437: // ! 438: // Have we run out of Mdl Chain in this request? ! 439: // ! 440: ! 441: if ((PacketBytes < FrameSize) || ! 442: (Connection->sp.CurrentSendMdl == NULL) || ! 443: (Connection->CurrentSendLength <= Connection->sp.MessageBytesSent)) { ! 444: ! 445: // ! 446: // Yep. We know that we've exhausted the current request's buffer ! 447: // here, so see if there's another request without EOF set that we ! 448: // can build start throwing into this packet. ! 449: // ! 450: ! 451: ! 452: if (!(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL)) { ! 453: ! 454: // ! 455: // We are sending the last packet in a message. Change ! 456: // the packet type to a "last" frame. ! 457: // ! 458: ! 459: StHeader->Flags |= ST_FLAGS_LAST; ! 460: Packet->CompleteSend = TRUE; ! 461: Connection->SendState = CONNECTION_SENDSTATE_IDLE; ! 462: ! 463: } else { ! 464: ! 465: // ! 466: // We are sending the last packet in this request. If there ! 467: // are more requests in the connection's SendQueue, then ! 468: // advance complex send pointer to point to the next one ! 469: // in line. Otherwise, if there aren't any more requests ! 470: // ready to packetize, then we enter the W_EOR state and ! 471: // stop packetizing. Note that we're waiting here for the TDI ! 472: // client to come up with data to send; we're just hanging out ! 473: // until then. ! 474: // ! 475: ! 476: if (Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink == &Connection->SendQueue) { ! 477: ! 478: Connection->SendState = CONNECTION_SENDSTATE_W_EOR; ! 479: ! 480: } else { ! 481: ! 482: Connection->sp.CurrentSendIrp = ! 483: CONTAINING_RECORD ( ! 484: Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink, ! 485: IRP, ! 486: Tail.Overlay.ListEntry); ! 487: Connection->sp.CurrentSendMdl = ! 488: Connection->sp.CurrentSendIrp->MdlAddress; ! 489: Connection->sp.SendByteOffset = 0; ! 490: Connection->CurrentSendLength += ! 491: IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp)); ! 492: } ! 493: } ! 494: } ! 495: ! 496: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 497: ! 498: LastPacketLength = sizeof(ST_HEADER) + PacketBytes; ! 499: ! 500: MacModifyHeader( ! 501: &DeviceContext->MacInfo, ! 502: Packet->Header, ! 503: LastPacketLength); ! 504: ! 505: Packet->NdisIFrameLength = LastPacketLength; ! 506: ! 507: StNdisSend (Packet); ! 508: ! 509: // ! 510: // Update our counters (this is done unprotected by a lock). ! 511: // ! 512: ! 513: ADD_TO_LARGE_INTEGER( ! 514: &DeviceContext->IFrameBytesSent, ! 515: PacketBytes, ! 516: &DeviceContext->StatisticsSpinLock); ! 517: ++DeviceContext->IFramesSent; ! 518: ! 519: } else { ! 520: ! 521: // ! 522: // BuildBufferChainFromMdlChain failed; we need to ! 523: // release the lock since the long if() above ! 524: // exits with it released. ! 525: // ! 526: ! 527: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 528: ! 529: } ! 530: ! 531: // ! 532: // Note that we may have fallen out of the BuildBuffer... if above with ! 533: // Status set to STATUS_INSUFFICIENT_RESOURCES. if we have, we'll just ! 534: // stick this connection back onto the packetize queue and hope the ! 535: // system gets more resources later. ! 536: // ! 537: ! 538: ! 539: if (!NT_SUCCESS (Status)) { ! 540: ! 541: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 542: ! 543: // ! 544: // Restore old complex send pointer. ! 545: // ! 546: ! 547: Connection->sp = SavedSendPointer; ! 548: ! 549: ! 550: // ! 551: // Indicate we're waiting on favorable link conditions. ! 552: // ! 553: ! 554: Connection->SendState = CONNECTION_SENDSTATE_W_LINK; ! 555: ! 556: // ! 557: // Clear the PACKETIZE flag, indicating that we're no longer ! 558: // on the PacketizeQueue or actively packetizing. The flag ! 559: // was set by StartPacketizingConnection to indicate that ! 560: // the connection was already on the PacketizeQueue. ! 561: // ! 562: ! 563: Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE; ! 564: ! 565: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 566: ! 567: StDestroyPacket (Packet); ! 568: StDereferenceSendIrp("Send failed", IrpSp); ! 569: StDereferenceConnection ("Send failed", Connection); ! 570: ! 571: return; ! 572: } ! 573: ! 574: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 575: ! 576: // ! 577: // It is probable that a frame arrived while we released ! 578: // the connection's spin lock, so our state has probably changed. ! 579: // When we cycle around this loop again, we will have the lock ! 580: // again, so we can test the connection's send state. ! 581: // ! 582: ! 583: } while (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE); ! 584: ! 585: // ! 586: // Clear the PACKETIZE flag, indicating that we're no longer on the ! 587: // PacketizeQueue or actively packetizing. The flag was set by ! 588: // StartPacketizingConnection to indicate that the connection was ! 589: // already on the PacketizeQueue. ! 590: // ! 591: ! 592: Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE; ! 593: ! 594: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 595: ! 596: StDereferenceConnection ("PacketizeSend done", Connection); ! 597: ! 598: } /* PacketizeSend */ ! 599: ! 600: ! 601: VOID ! 602: CompleteSend( ! 603: PTP_CONNECTION Connection ! 604: ) ! 605: ! 606: /*++ ! 607: ! 608: Routine Description: ! 609: ! 610: This routine is called to complete a TDI send back to the ! 611: caller. In the sample transport we assume that all sends ! 612: complete successfully, but in other transports we would ! 613: wait for a response from the remote. ! 614: ! 615: Arguments: ! 616: ! 617: Connection - Pointer to a TP_CONNECTION object. ! 618: ! 619: Return Value: ! 620: ! 621: none. ! 622: ! 623: --*/ ! 624: ! 625: { ! 626: KIRQL oldirql, cancelirql; ! 627: PIRP Irp; ! 628: PIO_STACK_LOCATION IrpSp; ! 629: PLIST_ENTRY p; ! 630: BOOLEAN EndOfRecord; ! 631: ! 632: // ! 633: // Pick off TP_REQUEST objects from the connection's SendQueue until ! 634: // we find one with an END_OF_RECORD mark embedded in it. ! 635: // ! 636: ! 637: IoAcquireCancelSpinLock(&cancelirql); ! 638: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 639: ! 640: while (TRUE) { ! 641: ! 642: // ! 643: // We know for a fact that we wouldn't be calling this routine if ! 644: // we hadn't completed sending an entire message, since we ! 645: // only set the ST_LAST bit in that case. Therefore, we ! 646: // know that we will run into a request with the END_OF_RECORD ! 647: // mark set BEFORE we will run out of requests on that queue, ! 648: // so there is no reason to check to see if we ran off the end. ! 649: // Note that it's possible that the send has been failed and the ! 650: // connection not yet torn down; if this has happened, we could be ! 651: // removing from an empty queue here. Make sure that doesn't happen. ! 652: // ! 653: ! 654: if (Connection->SendQueue.Flink == &Connection->SendQueue) { ! 655: ! 656: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 657: IoReleaseCancelSpinLock(cancelirql); ! 658: ! 659: // ! 660: // no requests to complete, things must have failed; just get out. ! 661: // ! 662: ! 663: break; ! 664: } ! 665: ! 666: p = RemoveHeadList (&Connection->SendQueue); ! 667: ! 668: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 669: Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry); ! 670: IrpSp = IoGetCurrentIrpStackLocation (Irp); ! 671: ! 672: EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL); ! 673: ! 674: Irp->CancelRoutine = (PDRIVER_CANCEL)NULL; ! 675: IoReleaseCancelSpinLock(cancelirql); ! 676: ! 677: // ! 678: // Complete the send. Note that this may not actually call ! 679: // IoCompleteRequest for the Irp until sometime later, if the ! 680: // in-progress LLC resending going on below us needs to complete. ! 681: // ! 682: ! 683: StCompleteSendIrp ( ! 684: Irp, ! 685: STATUS_SUCCESS, ! 686: IRP_SEND_LENGTH(IrpSp)); ! 687: ! 688: if (EndOfRecord) { ! 689: break; ! 690: } ! 691: ! 692: IoAcquireCancelSpinLock(&cancelirql); ! 693: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 694: ! 695: }; ! 696: ! 697: // ! 698: // Acquire the lock that we will return with. ! 699: // ! 700: ! 701: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 702: ! 703: // ! 704: // We've finished processing the current send. Update our state. ! 705: // ! 706: ! 707: Connection->SendState = CONNECTION_SENDSTATE_IDLE; ! 708: ! 709: // ! 710: // If there is another send pending on the connection, then initialize ! 711: // it and start packetizing it. ! 712: // ! 713: ! 714: if (!(IsListEmpty (&Connection->SendQueue))) { ! 715: ! 716: InitializeSend (Connection); ! 717: ! 718: // ! 719: // This code is similar to calling StartPacketizingConnection ! 720: // with the second parameter FALSE. ! 721: // ! 722: ! 723: if ((!(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) && ! 724: (!(Connection->Flags & CONNECTION_FLAGS_STOPPING))) { ! 725: ! 726: Connection->Flags |= CONNECTION_FLAGS_PACKETIZE; ! 727: ! 728: StReferenceConnection ("Packetize", Connection); ! 729: ! 730: ExInterlockedInsertTailList( ! 731: &Connection->Provider->PacketizeQueue, ! 732: &Connection->PacketizeLinkage, ! 733: &Connection->Provider->SpinLock); ! 734: ! 735: } ! 736: ! 737: } ! 738: ! 739: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 740: ! 741: } /* CompleteSend */ ! 742: ! 743: ! 744: VOID ! 745: FailSend( ! 746: IN PTP_CONNECTION Connection, ! 747: IN NTSTATUS RequestStatus, ! 748: IN BOOLEAN StopConnection ! 749: ) ! 750: ! 751: /*++ ! 752: ! 753: Routine Description: ! 754: ! 755: This routine is called because something on the link caused this send to be ! 756: unable to complete. There are a number of possible reasons for this to have ! 757: happened, but all will fail with the common error STATUS_LINK_FAILED. ! 758: or NO_RECEIVE response where the number of bytes specified exactly ! 759: Here we retire all of the TdiSends on the connection's SendQueue up to ! 760: and including the current one, which is the one that failed. ! 761: ! 762: Later - Actually, a send failing is cause for the entire circuit to wave ! 763: goodbye to this life. We now simply tear down the connection completly. ! 764: Any future sends on this connection will be blown away. ! 765: ! 766: Arguments: ! 767: ! 768: Connection - Pointer to a TP_CONNECTION object. ! 769: ! 770: Return Value: ! 771: ! 772: none. ! 773: ! 774: --*/ ! 775: ! 776: { ! 777: KIRQL oldirql, cancelirql; ! 778: PIRP Irp; ! 779: PIO_STACK_LOCATION IrpSp; ! 780: PLIST_ENTRY p; ! 781: BOOLEAN EndOfRecord; ! 782: BOOLEAN GotCurrent = FALSE; ! 783: ! 784: ! 785: // ! 786: // Pick off IRP objects from the connection's SendQueue until ! 787: // we get to this one. If this one does NOT have an EOF mark set, we'll ! 788: // need to keep going until we hit one that does have EOF set. Note that ! 789: // this may cause us to continue failing sends that have not yet been ! 790: // queued. (We do all this because ST does not provide stream mode sends.) ! 791: // ! 792: ! 793: IoAcquireCancelSpinLock(&cancelirql); ! 794: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 795: StReferenceConnection ("Failing Send", Connection); ! 796: ! 797: do { ! 798: if (IsListEmpty (&Connection->SendQueue)) { ! 799: ! 800: // ! 801: // got an empty list, so we've run out of send requests to fail ! 802: // without running into an EOR. Set the connection flag that will ! 803: // cause all further sends to be failed up to an EOR and get out ! 804: // of here. ! 805: // ! 806: ! 807: Connection->Flags |= CONNECTION_FLAGS_FAILING_TO_EOR; ! 808: break; ! 809: } ! 810: p = RemoveHeadList (&Connection->SendQueue); ! 811: Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry); ! 812: IrpSp = IoGetCurrentIrpStackLocation (Irp); ! 813: ! 814: if (Irp == Connection->sp.CurrentSendIrp) { ! 815: GotCurrent = TRUE; ! 816: } ! 817: EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL); ! 818: ! 819: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 820: Irp->CancelRoutine = (PDRIVER_CANCEL)NULL; ! 821: IoReleaseCancelSpinLock(cancelirql); ! 822: ! 823: ! 824: // ! 825: // The following dereference will complete the I/O, provided removes ! 826: // the last reference on the request object. The I/O will complete ! 827: // with the status and information stored in the Irp. Therefore, ! 828: // we set those values here before the dereference. ! 829: // ! 830: ! 831: StCompleteSendIrp (Irp, RequestStatus, 0); ! 832: IoAcquireCancelSpinLock(&cancelirql); ! 833: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 834: } while (!EndOfRecord & !GotCurrent); ! 835: ! 836: // ! 837: // We've finished processing the current send. Update our state. ! 838: // ! 839: ! 840: Connection->SendState = CONNECTION_SENDSTATE_IDLE; ! 841: Connection->sp.CurrentSendIrp = NULL; ! 842: ! 843: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 844: IoReleaseCancelSpinLock(cancelirql); ! 845: ! 846: ! 847: if (StopConnection) { ! 848: StStopConnection (Connection, STATUS_LINK_FAILED); ! 849: } ! 850: ! 851: StDereferenceConnection ("FailSend", Connection); ! 852: ! 853: } /* FailSend */ ! 854: ! 855: ! 856: VOID ! 857: InitializeSend( ! 858: PTP_CONNECTION Connection ! 859: ) ! 860: ! 861: /*++ ! 862: ! 863: Routine Description: ! 864: ! 865: This routine is called whenever the next send on a connection should ! 866: be initialized; that is, all of the fields associated with the state ! 867: of the current send are set to refer to the first send on the SendQueue. ! 868: ! 869: WARNING: This routine is executed with the Connection lock acquired ! 870: since it must be atomically executed with the caller's setup. ! 871: ! 872: Arguments: ! 873: ! 874: Connection - Pointer to a TP_CONNECTION object. ! 875: ! 876: Return Value: ! 877: ! 878: none. ! 879: ! 880: --*/ ! 881: ! 882: { ! 883: if (Connection->SendQueue.Flink != &Connection->SendQueue) { ! 884: Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE; ! 885: Connection->FirstSendIrp = ! 886: CONTAINING_RECORD (Connection->SendQueue.Flink, IRP, Tail.Overlay.ListEntry); ! 887: Connection->FirstSendMdl = Connection->FirstSendIrp->MdlAddress; ! 888: Connection->FirstSendByteOffset = 0; ! 889: Connection->sp.MessageBytesSent = 0; ! 890: Connection->sp.CurrentSendIrp = Connection->FirstSendIrp; ! 891: Connection->sp.CurrentSendMdl = Connection->FirstSendMdl; ! 892: Connection->sp.SendByteOffset = Connection->FirstSendByteOffset; ! 893: Connection->CurrentSendLength = ! 894: IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp)); ! 895: ! 896: } ! 897: } /* InitializeSend */ ! 898: ! 899: ! 900: VOID ! 901: StCancelSend( ! 902: IN PDEVICE_OBJECT DeviceObject, ! 903: IN PIRP Irp ! 904: ) ! 905: ! 906: /*++ ! 907: ! 908: Routine Description: ! 909: ! 910: This routine is called by the I/O system to cancel a send. ! 911: The send is found on the connection's send queue; if it is the ! 912: current request it is cancelled and the connection is torn down, ! 913: otherwise it is silently cancelled. ! 914: ! 915: NOTE: This routine is called with the CancelSpinLock held and ! 916: is responsible for releasing it. ! 917: ! 918: Arguments: ! 919: ! 920: DeviceObject - Pointer to the device object for this driver. ! 921: ! 922: Irp - Pointer to the request packet representing the I/O request. ! 923: ! 924: Return Value: ! 925: ! 926: none. ! 927: ! 928: --*/ ! 929: ! 930: { ! 931: KIRQL oldirql; ! 932: PIO_STACK_LOCATION IrpSp; ! 933: PTP_CONNECTION Connection; ! 934: PIRP SendIrp; ! 935: PLIST_ENTRY p; ! 936: BOOLEAN Found; ! 937: ! 938: UNREFERENCED_PARAMETER (DeviceObject); ! 939: ! 940: // ! 941: // Get a pointer to the current stack location in the IRP. This is where ! 942: // the function codes and parameters are stored. ! 943: // ! 944: ! 945: IrpSp = IoGetCurrentIrpStackLocation (Irp); ! 946: ! 947: ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) && ! 948: (IrpSp->MinorFunction == TDI_SEND)); ! 949: ! 950: Connection = IrpSp->FileObject->FsContext; ! 951: ! 952: // ! 953: // Since this IRP is still in the cancellable state, we know ! 954: // that the connection is still around (although it may be in ! 955: // the process of being torn down). ! 956: // ! 957: ! 958: // ! 959: // See if this is the IRP for the current send request. ! 960: // ! 961: ! 962: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 963: StReferenceConnection ("Cancelling Send", Connection); ! 964: ! 965: p = Connection->SendQueue.Flink; ! 966: SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry); ! 967: ! 968: if (SendIrp == Irp) { ! 969: ! 970: // ! 971: // yes, it is the first one on the send queue, so ! 972: // trash the send/connection. ! 973: // ! 974: ! 975: p = RemoveHeadList (&Connection->SendQueue); ! 976: ! 977: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 978: IoReleaseCancelSpinLock (Irp->CancelIrql); ! 979: ! 980: ! 981: // ! 982: // The following dereference will complete the I/O, provided removes ! 983: // the last reference on the request object. The I/O will complete ! 984: // with the status and information stored in the Irp. Therefore, ! 985: // we set those values here before the dereference. ! 986: // ! 987: ! 988: StCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0); ! 989: ! 990: // ! 991: // Since we are cancelling the current send, blow away ! 992: // the connection. ! 993: // ! 994: ! 995: StStopConnection (Connection, STATUS_CANCELLED); ! 996: ! 997: } else { ! 998: ! 999: // ! 1000: // Scan through the list, looking for this IRP. ! 1001: // ! 1002: ! 1003: Found = FALSE; ! 1004: p = p->Flink; ! 1005: while (p != &Connection->SendQueue) { ! 1006: ! 1007: SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry); ! 1008: if (SendIrp == Irp) { ! 1009: ! 1010: // ! 1011: // Found it, remove it from the list here. ! 1012: // ! 1013: ! 1014: RemoveEntryList (p); ! 1015: ! 1016: Found = TRUE; ! 1017: ! 1018: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1019: IoReleaseCancelSpinLock (Irp->CancelIrql); ! 1020: ! 1021: // ! 1022: // The following dereference will complete the I/O, provided removes ! 1023: // the last reference on the request object. The I/O will complete ! 1024: // with the status and information stored in the Irp. Therefore, ! 1025: // we set those values here before the dereference. ! 1026: // ! 1027: ! 1028: StCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0); ! 1029: break; ! 1030: ! 1031: } ! 1032: ! 1033: p = p->Flink; ! 1034: ! 1035: } ! 1036: ! 1037: if (!Found) { ! 1038: ! 1039: // ! 1040: // We didn't find it! ! 1041: // ! 1042: ! 1043: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1044: IoReleaseCancelSpinLock (Irp->CancelIrql); ! 1045: } ! 1046: ! 1047: } ! 1048: ! 1049: StDereferenceConnection ("Cancelling Send", Connection); ! 1050: ! 1051: } ! 1052: ! 1053: ! 1054: ! 1055: VOID ! 1056: StSendCompletionHandler( ! 1057: IN NDIS_HANDLE ProtocolBindingContext, ! 1058: IN PNDIS_PACKET NdisPacket, ! 1059: IN NDIS_STATUS NdisStatus ! 1060: ) ! 1061: ! 1062: /*++ ! 1063: ! 1064: Routine Description: ! 1065: ! 1066: This routine is called by the I/O system to indicate that a connection- ! 1067: oriented packet has been shipped and is no longer needed by the Physical ! 1068: Provider. ! 1069: ! 1070: Arguments: ! 1071: ! 1072: NdisContext - the value associated with the adapter binding at adapter ! 1073: open time (which adapter we're talking on). ! 1074: ! 1075: NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent. ! 1076: ! 1077: NdisStatus - the completion status of the send. ! 1078: ! 1079: Return Value: ! 1080: ! 1081: none. ! 1082: ! 1083: --*/ ! 1084: ! 1085: { ! 1086: PSEND_PACKET_TAG SendContext; ! 1087: PTP_PACKET Packet; ! 1088: KIRQL oldirql, cancelirql; ! 1089: PDEVICE_CONTEXT DeviceContext; ! 1090: PTP_CONNECTION Connection; ! 1091: PLIST_ENTRY p; ! 1092: PIO_STACK_LOCATION IrpSp; ! 1093: PTP_REQUEST request; ! 1094: TA_NETBIOS_ADDRESS TempAddress; ! 1095: ULONG returnLength; ! 1096: NTSTATUS status; ! 1097: PTDI_CONNECTION_INFORMATION remoteInformation; ! 1098: ! 1099: UNREFERENCED_PARAMETER(ProtocolBindingContext); ! 1100: ! 1101: SendContext = (PSEND_PACKET_TAG)&NdisPacket->ProtocolReserved[0]; ! 1102: Packet = SendContext->Packet; ! 1103: ! 1104: DeviceContext = Packet->Provider; ! 1105: ! 1106: Packet->PacketSent = TRUE; ! 1107: ! 1108: switch (SendContext->Type) { ! 1109: ! 1110: case TYPE_I_FRAME: ! 1111: ! 1112: // ! 1113: // Dereference the IRP that this packet was sent for. ! 1114: // ! 1115: ! 1116: IrpSp = (PIO_STACK_LOCATION)(SendContext->Owner); ! 1117: ! 1118: if (Packet->CompleteSend) { ! 1119: CompleteSend(IRP_CONNECTION(IrpSp)); ! 1120: } ! 1121: StDereferenceSendIrp("Destroy packet", IrpSp); ! 1122: break; ! 1123: ! 1124: case TYPE_D_FRAME: ! 1125: ! 1126: // ! 1127: // Finish tearing down the connection. ! 1128: // ! 1129: ! 1130: StDereferenceConnection("Disconnect completed", (PTP_CONNECTION)(SendContext->Owner)); ! 1131: break; ! 1132: ! 1133: case TYPE_G_FRAME: ! 1134: ! 1135: // ! 1136: // Addresses get their own frames; let the address know it's ok to ! 1137: // use the frame again, and exit to avoid normal packet completion. ! 1138: // ! 1139: ! 1140: StSendDatagramCompletion ((PTP_ADDRESS)(SendContext->Owner), ! 1141: NdisPacket, ! 1142: NdisStatus); ! 1143: return; ! 1144: ! 1145: case TYPE_C_FRAME: ! 1146: ! 1147: // ! 1148: // Complete the TdiConnect request; note that he better ! 1149: // have accepted it quickly since we will immediately ! 1150: // start sending data if required. ! 1151: // ! 1152: ! 1153: Connection = (PTP_CONNECTION)(SendContext->Owner); ! 1154: ! 1155: IoAcquireCancelSpinLock (&cancelirql); ! 1156: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); ! 1157: ! 1158: p = RemoveHeadList (&Connection->InProgressRequest); ! 1159: ! 1160: // ! 1161: // Turn off the connection request timer if there is one, and set ! 1162: // this connection's state to READY. ! 1163: // ! 1164: ! 1165: Connection->Flags |= CONNECTION_FLAGS_READY; ! 1166: ! 1167: INCREMENT_COUNTER (Connection->Provider, OpenConnections); ! 1168: ! 1169: // ! 1170: // Record that the connect request has been successfully ! 1171: // completed by TpCompleteRequest. ! 1172: // ! 1173: ! 1174: Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED; ! 1175: ! 1176: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); ! 1177: ! 1178: // ! 1179: // Now complete the request and get out. ! 1180: // ! 1181: ! 1182: if (p == &Connection->InProgressRequest) { ! 1183: Connection->IndicationInProgress = FALSE; ! 1184: PANIC ("ProcessSessionConfirm: TdiConnect evaporated!\n"); ! 1185: IoReleaseCancelSpinLock (cancelirql); ! 1186: break; ! 1187: } ! 1188: ! 1189: // ! 1190: // We have a completed connection with a queued connect. Complete ! 1191: // the connect. ! 1192: // ! 1193: ! 1194: request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); ! 1195: request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL; ! 1196: IoReleaseCancelSpinLock(cancelirql); ! 1197: ! 1198: IrpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket); ! 1199: remoteInformation = ! 1200: ((PTDI_REQUEST_KERNEL)(&IrpSp->Parameters))->ReturnConnectionInformation; ! 1201: if (remoteInformation != NULL) { ! 1202: try { ! 1203: if (remoteInformation->RemoteAddressLength != 0) { ! 1204: ! 1205: // ! 1206: // Build a temporary TA_NETBIOS_ADDRESS, then ! 1207: // copy over as many bytes as fit. ! 1208: // ! 1209: ! 1210: TdiBuildNetbiosAddress( ! 1211: Connection->CalledAddress.NetbiosName, ! 1212: (BOOLEAN)(Connection->CalledAddress.NetbiosNameType == ! 1213: TDI_ADDRESS_NETBIOS_TYPE_GROUP), ! 1214: &TempAddress); ! 1215: ! 1216: if (remoteInformation->RemoteAddressLength >= ! 1217: sizeof (TA_NETBIOS_ADDRESS)) { ! 1218: ! 1219: returnLength = sizeof(TA_NETBIOS_ADDRESS); ! 1220: remoteInformation->RemoteAddressLength = returnLength; ! 1221: ! 1222: } else { ! 1223: ! 1224: returnLength = remoteInformation->RemoteAddressLength; ! 1225: ! 1226: } ! 1227: ! 1228: RtlCopyMemory( ! 1229: (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress, ! 1230: &TempAddress, ! 1231: returnLength); ! 1232: ! 1233: } else { ! 1234: ! 1235: returnLength = 0; ! 1236: } ! 1237: ! 1238: status = STATUS_SUCCESS; ! 1239: ! 1240: } except (EXCEPTION_EXECUTE_HANDLER) { ! 1241: ! 1242: returnLength = 0; ! 1243: status = GetExceptionCode (); ! 1244: ! 1245: } ! 1246: ! 1247: } else { ! 1248: ! 1249: status = STATUS_SUCCESS; ! 1250: returnLength = 0; ! 1251: ! 1252: } ! 1253: ! 1254: RtlCopyMemory( Connection->RemoteName, Connection->CalledAddress.NetbiosName, 16 ); ! 1255: Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID; ! 1256: ! 1257: // ! 1258: // Reference the connection so it stays around after ! 1259: // the request is completed. ! 1260: // ! 1261: ! 1262: StReferenceConnection("Connect completed", Connection); ! 1263: ! 1264: StCompleteRequest (request, status, returnLength); ! 1265: ! 1266: break; ! 1267: ! 1268: } ! 1269: ! 1270: StDestroyPacket(Packet); ! 1271: ! 1272: } /* StSendCompletionHandler */ ! 1273: ! 1274: ! 1275: VOID ! 1276: StNdisSend( ! 1277: IN PTP_PACKET Packet ! 1278: ) ! 1279: ! 1280: /*++ ! 1281: ! 1282: Routine Description: ! 1283: ! 1284: This routine sends an NDIS packet ! 1285: This routine is used to ensure that receive sequence numbers on ! 1286: packets are numbered correctly. It is called in place of NdisSend ! 1287: and after assigning the receive sequence number it locks out other ! 1288: sends until the NdisSend call has returned (not necessarily completed), ! 1289: insuring that the packets with increasing receive sequence numbers ! 1290: are queue in the right order by the MAC. ! 1291: ! 1292: NOTE: This routine is called with the link spinlock held, ! 1293: and it returns with it released. ! 1294: ! 1295: Arguments: ! 1296: ! 1297: Packet - Pointer to a TP_PACKET object. ! 1298: ! 1299: Return Value: ! 1300: ! 1301: None. ! 1302: ! 1303: --*/ ! 1304: ! 1305: { ! 1306: ! 1307: NDIS_STATUS NdisStatus; ! 1308: ! 1309: NdisSend ( ! 1310: &NdisStatus, ! 1311: ((PDEVICE_CONTEXT)(Packet->Provider))->NdisBindingHandle, ! 1312: Packet->NdisPacket); ! 1313: ! 1314: if (NdisStatus != NDIS_STATUS_PENDING) { ! 1315: ! 1316: StSendCompletionHandler( ! 1317: Packet->Provider, ! 1318: Packet->NdisPacket, ! 1319: NdisStatus); ! 1320: } ! 1321: ! 1322: } /* StNdisSend */ ! 1323: ! 1324: ! 1325: ! 1326: NTSTATUS ! 1327: BuildBufferChainFromMdlChain ( ! 1328: IN NDIS_HANDLE BufferPoolHandle, ! 1329: IN PMDL CurrentMdl, ! 1330: IN ULONG ByteOffset, ! 1331: IN ULONG DesiredLength, ! 1332: OUT PNDIS_BUFFER *Destination, ! 1333: OUT PMDL *NewCurrentMdl, ! 1334: OUT ULONG *NewByteOffset, ! 1335: OUT ULONG *TrueLength ! 1336: ) ! 1337: ! 1338: /*++ ! 1339: ! 1340: Routine Description: ! 1341: ! 1342: This routine is called to build an NDIS_BUFFER chain from a source Mdl chain and ! 1343: offset into it. We assume we don't know the length of the source Mdl chain, ! 1344: and we must allocate the NDIS_BUFFERs for the destination chain, which ! 1345: we do from the NDIS buffer pool. ! 1346: ! 1347: The NDIS_BUFFERs that are returned are mapped and locked. (Actually, the pages in ! 1348: them are in the same state as those in the source MDLs.) ! 1349: ! 1350: If the system runs out of memory while we are building the destination ! 1351: NDIS_BUFFER chain, we completely clean up the built chain and return with ! 1352: NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl ! 1353: and ByteOffset. TrueLength is set to 0. ! 1354: ! 1355: Environment: ! 1356: ! 1357: Kernel Mode, Source Mdls locked. It is recommended, although not required, ! 1358: that the source Mdls be mapped and locked prior to calling this routine. ! 1359: ! 1360: Arguments: ! 1361: ! 1362: BufferPoolHandle - The buffer pool to allocate buffers from. ! 1363: ! 1364: CurrentMdl - Points to the start of the Mdl chain from which to draw the ! 1365: packet. ! 1366: ! 1367: ByteOffset - Offset within this MDL to start the packet at. ! 1368: ! 1369: DesiredLength - The number of bytes to insert into the packet. ! 1370: ! 1371: Destination - returned pointer to the NDIS_BUFFER chain describing the packet. ! 1372: ! 1373: NewCurrentMdl - returned pointer to the Mdl that would be used for the next ! 1374: byte of packet. NULL if the source Mdl chain was exhausted. ! 1375: ! 1376: NewByteOffset - returned offset into the NewCurrentMdl for the next byte of ! 1377: packet. NULL if the source Mdl chain was exhausted. ! 1378: ! 1379: TrueLength - The actual length of the returned NDIS_BUFFER Chain. If less than ! 1380: DesiredLength, the source Mdl chain was exhausted. ! 1381: ! 1382: Return Value: ! 1383: ! 1384: STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded (even if ! 1385: shorter than the desired chain). ! 1386: ! 1387: STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while building the ! 1388: destination chain. ! 1389: ! 1390: --*/ ! 1391: { ! 1392: ULONG AvailableBytes; ! 1393: PMDL OldMdl; ! 1394: PNDIS_BUFFER NewNdisBuffer; ! 1395: NDIS_STATUS NdisStatus; ! 1396: ! 1397: ! 1398: AvailableBytes = MmGetMdlByteCount (CurrentMdl) - ByteOffset; ! 1399: if (AvailableBytes > DesiredLength) { ! 1400: AvailableBytes = DesiredLength; ! 1401: } ! 1402: ! 1403: OldMdl = CurrentMdl; ! 1404: *NewCurrentMdl = OldMdl; ! 1405: *NewByteOffset = ByteOffset + AvailableBytes; ! 1406: *TrueLength = AvailableBytes; ! 1407: ! 1408: ! 1409: // ! 1410: // Build the first NDIS_BUFFER, which could conceivably be the only one... ! 1411: // ! 1412: ! 1413: NdisCopyBuffer( ! 1414: &NdisStatus, ! 1415: &NewNdisBuffer, ! 1416: BufferPoolHandle, ! 1417: OldMdl, ! 1418: ByteOffset, ! 1419: AvailableBytes); ! 1420: ! 1421: ! 1422: if (NdisStatus != NDIS_STATUS_SUCCESS) { ! 1423: *NewByteOffset = ByteOffset; ! 1424: *TrueLength = 0; ! 1425: *Destination = NULL; ! 1426: return STATUS_INSUFFICIENT_RESOURCES; ! 1427: } ! 1428: ! 1429: *Destination = NewNdisBuffer; ! 1430: ! 1431: // ! 1432: // Was the first NDIS_BUFFER enough data, or are we out of Mdls? ! 1433: // ! 1434: ! 1435: if ((AvailableBytes == DesiredLength) || (OldMdl->Next == NULL)) { ! 1436: if (*NewByteOffset >= MmGetMdlByteCount (OldMdl)) { ! 1437: *NewCurrentMdl = OldMdl->Next; ! 1438: *NewByteOffset = 0; ! 1439: } ! 1440: return STATUS_SUCCESS; ! 1441: } ! 1442: ! 1443: // ! 1444: // Need more data, so follow the in Mdl chain to create a packet. ! 1445: // ! 1446: ! 1447: OldMdl = OldMdl->Next; ! 1448: *NewCurrentMdl = OldMdl; ! 1449: ! 1450: while (OldMdl != NULL) { ! 1451: AvailableBytes = DesiredLength - *TrueLength; ! 1452: if (AvailableBytes > MmGetMdlByteCount (OldMdl)) { ! 1453: AvailableBytes = MmGetMdlByteCount (OldMdl); ! 1454: } ! 1455: ! 1456: NdisCopyBuffer( ! 1457: &NdisStatus, ! 1458: &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)), ! 1459: BufferPoolHandle, ! 1460: OldMdl, ! 1461: 0, ! 1462: AvailableBytes); ! 1463: ! 1464: if (NdisStatus != NDIS_STATUS_SUCCESS) { ! 1465: ! 1466: // ! 1467: // ran out of resources. put back what we've used in this call and ! 1468: // return the error. ! 1469: // ! 1470: ! 1471: while (*Destination != NULL) { ! 1472: NewNdisBuffer = NDIS_BUFFER_LINKAGE(*Destination); ! 1473: NdisFreeBuffer (*Destination); ! 1474: *Destination = NewNdisBuffer; ! 1475: } ! 1476: ! 1477: *NewByteOffset = ByteOffset; ! 1478: *TrueLength = 0; ! 1479: *NewCurrentMdl = CurrentMdl; ! 1480: ! 1481: return STATUS_INSUFFICIENT_RESOURCES; ! 1482: } ! 1483: ! 1484: NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer); ! 1485: ! 1486: *TrueLength += AvailableBytes; ! 1487: *NewByteOffset = AvailableBytes; ! 1488: ! 1489: if (*TrueLength == DesiredLength) { ! 1490: if (*NewByteOffset == MmGetMdlByteCount (OldMdl)) { ! 1491: *NewCurrentMdl = OldMdl->Next; ! 1492: *NewByteOffset = 0; ! 1493: } ! 1494: return STATUS_SUCCESS; ! 1495: } ! 1496: OldMdl = OldMdl->Next; ! 1497: *NewCurrentMdl = OldMdl; ! 1498: ! 1499: } // while (mdl chain exists) ! 1500: ! 1501: *NewCurrentMdl = NULL; ! 1502: *NewByteOffset = 0; ! 1503: return STATUS_SUCCESS; ! 1504: ! 1505: } // BuildBufferChainFromMdlChain ! 1506:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.