|
|
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.