|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1989-1993 Microsoft Corporation
4:
5: Module Name:
6:
7: request.c
8:
9: Abstract:
10:
11: This module contains code which implements the TP_REQUEST object.
12: Routines are provided to create, destroy, reference, and dereference,
13: transport request objects.
14:
15: Environment:
16:
17: Kernel mode
18:
19: Revision History:
20:
21:
22: --*/
23:
24: #include "st.h"
25:
26:
27: VOID
28: StTdiRequestTimeoutHandler(
29: IN PKDPC Dpc,
30: IN PVOID DeferredContext,
31: IN PVOID SystemArgument1,
32: IN PVOID SystemArgument2
33: )
34:
35: /*++
36:
37: Routine Description:
38:
39: This routine is executed as a DPC at DISPATCH_LEVEL when a request
40: such as TdiSend, TdiReceive, TdiSendDatagram, TdiReceiveDatagram, etc.,
41: encounters a timeout. This routine cleans up the activity and cancels it.
42:
43: Arguments:
44:
45: Dpc - Pointer to a system DPC object.
46:
47: DeferredContext - Pointer to the TP_REQUEST block representing the
48: request that has timed out.
49:
50: SystemArgument1 - Not used.
51:
52: SystemArgument2 - Not used.
53:
54: Return Value:
55:
56: none.
57:
58: --*/
59:
60: {
61: KIRQL oldirql;
62: PTP_REQUEST Request;
63: PTP_CONNECTION Connection;
64: PIO_STACK_LOCATION IrpSp;
65:
66: UNREFERENCED_PARAMETER(Dpc);
67: UNREFERENCED_PARAMETER(SystemArgument1);
68: UNREFERENCED_PARAMETER(SystemArgument2);
69:
70:
71: Request = (PTP_REQUEST)DeferredContext;
72:
73: ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
74: Request->Flags &= ~REQUEST_FLAGS_TIMER;
75: if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
76:
77: //
78: // find reason for timeout
79: //
80:
81: IrpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
82: if (IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) {
83: switch (IrpSp->MinorFunction) {
84:
85: //
86: // none of these should time out.
87: //
88:
89: case TDI_SEND:
90: case TDI_ACCEPT:
91: case TDI_SET_INFORMATION:
92: case TDI_SET_EVENT_HANDLER:
93: case TDI_SEND_DATAGRAM:
94: case TDI_RECEIVE_DATAGRAM:
95: case TDI_RECEIVE:
96:
97: ASSERT (FALSE);
98: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
99: StCompleteRequest (Request, STATUS_IO_TIMEOUT, 0);
100: break;
101:
102:
103: case TDI_LISTEN:
104: case TDI_CONNECT:
105:
106: Connection = (PTP_CONNECTION)(Request->Context);
107: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
108:
109: //
110: // Since these requests are part of the connection
111: // itself, we just stop the connection and the
112: // request will get torn down then. If we get the
113: // situation where the request times out before
114: // it is queued to the connection, then the code
115: // that is about to queue it will check the STOPPING
116: // flag and complete it then.
117: //
118:
119: StStopConnection (Connection, STATUS_IO_TIMEOUT);
120: break;
121:
122: case TDI_DISCONNECT:
123:
124: //
125: // We don't create requests for TDI_DISCONNECT any more.
126: //
127:
128: ASSERT(FALSE);
129: break;
130:
131: default:
132: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
133: break;
134:
135: } // end of switch
136:
137: } else {
138:
139: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
140:
141: }
142:
143: StDereferenceRequest ("Timeout", Request); // for the timeout
144:
145: } else {
146:
147: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
148: StDereferenceRequest ("Timeout: stopping", Request); // for the timeout
149:
150: }
151:
152: return;
153:
154: } /* RequestTimeoutHandler */
155:
156:
157: VOID
158: StAllocateRequest(
159: IN PDEVICE_CONTEXT DeviceContext,
160: OUT PTP_REQUEST *TransportRequest
161: )
162:
163: /*++
164:
165: Routine Description:
166:
167: This routine allocates a request packet from nonpaged pool and initializes
168: it to a known state.
169:
170: NOTE: This routine is called with the device context spinlock
171: held, or at such a time as synchronization is unnecessary.
172:
173: Arguments:
174:
175: DeviceContext - Pointer to the device context (which is really just
176: the device object with its extension) to be associated with the
177: address.
178:
179: TransportRequest - Pointer to a place where this routine will return
180: a pointer to a transport request structure. It returns NULL if no
181: storage can be allocated.
182:
183: Return Value:
184:
185: None.
186:
187: --*/
188:
189: {
190: PTP_REQUEST Request;
191:
192: if ((DeviceContext->MemoryLimit != 0) &&
193: ((DeviceContext->MemoryUsage + sizeof(TP_REQUEST)) >
194: DeviceContext->MemoryLimit)) {
195: PANIC("ST: Could not allocate request: limit\n");
196: StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 104);
197: *TransportRequest = NULL;
198: return;
199: }
200:
201: Request = (PTP_REQUEST)ExAllocatePool (NonPagedPool, sizeof (TP_REQUEST));
202: if (Request == NULL) {
203: PANIC("ST: Could not allocate request: no pool\n");
204: StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 204);
205: *TransportRequest = NULL;
206: return;
207: }
208: RtlZeroMemory (Request, sizeof(TP_REQUEST));
209:
210: DeviceContext->MemoryUsage += sizeof(TP_REQUEST);
211: ++DeviceContext->RequestAllocated;
212:
213: Request->Type = ST_REQUEST_SIGNATURE;
214: Request->Size = sizeof (TP_REQUEST);
215:
216: Request->Provider = DeviceContext;
217: Request->ProviderInterlock = &DeviceContext->Interlock;
218: KeInitializeSpinLock (&Request->SpinLock);
219: KeInitializeDpc (&Request->Dpc, StTdiRequestTimeoutHandler, (PVOID)Request);
220: KeInitializeTimer (&Request->Timer); // set to not-signaled state.
221:
222: *TransportRequest = Request;
223:
224: } /* StAllocateRequest */
225:
226:
227: VOID
228: StDeallocateRequest(
229: IN PDEVICE_CONTEXT DeviceContext,
230: IN PTP_REQUEST TransportRequest
231: )
232:
233: /*++
234:
235: Routine Description:
236:
237: This routine frees a request packet.
238:
239: NOTE: This routine is called with the device context spinlock
240: held, or at such a time as synchronization is unnecessary.
241:
242: Arguments:
243:
244: DeviceContext - Pointer to the device context (which is really just
245: the device object with its extension) to be associated with the
246: address.
247:
248: TransportRequest - Pointer to a transport request structure.
249:
250: Return Value:
251:
252: None.
253:
254: --*/
255:
256: {
257:
258: ExFreePool (TransportRequest);
259: --DeviceContext->RequestAllocated;
260: DeviceContext->MemoryUsage -= sizeof(TP_REQUEST);
261:
262: } /* StDeallocateRequest */
263:
264:
265: NTSTATUS
266: StCreateRequest(
267: IN PIRP Irp,
268: IN PVOID Context,
269: IN ULONG Flags,
270: IN PMDL Buffer2,
271: IN ULONG Buffer2Length,
272: IN LARGE_INTEGER Timeout,
273: OUT PTP_REQUEST * TpRequest
274: )
275:
276: /*++
277:
278: Routine Description:
279:
280: This routine creates a transport request and associates it with the
281: specified IRP, context, and queue. All major requests, including
282: TdiSend, TdiSendDatagram, TdiReceive, and TdiReceiveDatagram requests,
283: are composed in this manner.
284:
285: Arguments:
286:
287: Irp - Pointer to an IRP which was received by the transport for this
288: request.
289:
290: Context - Pointer to anything to associate this request with. This
291: value is not interpreted except at request cancelation time.
292:
293: Flags - A set of bitflags indicating the disposition of this request.
294:
295: Timeout - Timeout value (if non-zero) to start a timer for this request.
296: If zero, then no timer is activated for the request.
297:
298: TpRequest - If the function returns STATUS_SUCCESS, this will return
299: pointer to the TP_REQUEST structure allocated.
300:
301: Return Value:
302:
303: NTSTATUS - status of operation.
304:
305: --*/
306:
307: {
308: KIRQL oldirql;
309: PDEVICE_CONTEXT DeviceContext;
310: PTP_REQUEST Request;
311: PLIST_ENTRY p;
312: PIO_STACK_LOCATION irpSp;
313:
314:
315: irpSp = IoGetCurrentIrpStackLocation(Irp);
316: DeviceContext = (PDEVICE_CONTEXT)irpSp->FileObject->DeviceObject;
317:
318: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
319:
320: p = RemoveHeadList (&DeviceContext->RequestPool);
321: if (p == &DeviceContext->RequestPool) {
322:
323: if ((DeviceContext->RequestMaxAllocated == 0) ||
324: (DeviceContext->RequestAllocated < DeviceContext->RequestMaxAllocated)) {
325:
326: StAllocateRequest (DeviceContext, &Request);
327:
328: } else {
329:
330: StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 404);
331: Request = NULL;
332:
333: }
334:
335: if (Request == NULL) {
336: ++DeviceContext->RequestExhausted;
337: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
338: PANIC ("StCreateConnection: Could not allocate request object!\n");
339: return STATUS_INSUFFICIENT_RESOURCES;
340: }
341:
342: } else {
343:
344: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
345:
346: }
347:
348: ++DeviceContext->RequestInUse;
349: if (DeviceContext->RequestInUse > DeviceContext->RequestMaxInUse) {
350: ++DeviceContext->RequestMaxInUse;
351: }
352:
353: DeviceContext->RequestTotal += DeviceContext->RequestInUse;
354: ++DeviceContext->RequestSamples;
355:
356: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
357:
358:
359: //
360: // fill out the request.
361: //
362:
363: // Request->Provider = DeviceContext;
364: Request->IoRequestPacket = Irp;
365: Request->Buffer2 = Buffer2;
366: Request->Buffer2Length = Buffer2Length;
367: Request->Flags = Flags;
368: Request->Context = Context;
369: Request->ReferenceCount = 1; // initialize reference count.
370:
371: if ((Timeout.LowPart == 0) && (Timeout.HighPart == 0)) {
372:
373: // no timeout
374: } else {
375:
376: Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
377: KeInitializeTimer (&Request->Timer); // set to not-signaled state.
378: StReferenceRequest ("Create: timer", Request); // one for the timer
379: KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
380: }
381:
382: *TpRequest = Request;
383:
384: return STATUS_SUCCESS;
385: } /* StCreateRequest */
386:
387:
388: VOID
389: StDestroyRequest(
390: IN PTP_REQUEST Request
391: )
392:
393: /*++
394:
395: Routine Description:
396:
397: This routine returns a request block to the free pool.
398:
399: Arguments:
400:
401: Request - Pointer to a TP_REQUEST block to return to the free pool.
402:
403: Return Value:
404:
405: NTSTATUS - status of operation.
406:
407: --*/
408:
409: {
410: KIRQL oldirql;
411: PIO_STACK_LOCATION irpSp;
412: PDEVICE_CONTEXT DeviceContext;
413:
414: //
415: // Return the request to the caller with whatever status is in the IRP.
416: //
417:
418: //
419: // Now dereference the owner of this request so that we are safe when
420: // we finally tear down the {connection, address}. The problem we're
421: // facing here is that we can't allow the user to assume semantics;
422: // the end of life for a connection must truly be the real end of life.
423: // for that to occur, we reference the owning object when the request is
424: // created and we dereference it just before we return it to the pool.
425: //
426:
427: switch (Request->Owner) {
428: case ConnectionType:
429: if (!(Request->Flags & REQUEST_FLAGS_DELAY)) {
430: StDereferenceConnection ("Removing Connection",((PTP_CONNECTION)Request->Context));
431: }
432: break;
433:
434: case AddressType:
435: StDereferenceAddress ("Removing Address", ((PTP_ADDRESS)Request->Context));
436: break;
437:
438: case DeviceContextType:
439: StDereferenceDeviceContext ("Removing Address", ((PDEVICE_CONTEXT)Request->Context));
440: break;
441: }
442:
443: irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
444: DeviceContext = Request->Provider;
445:
446: if (Request->Flags & REQUEST_FLAGS_DELAY) {
447:
448: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
449:
450: InsertTailList(
451: &DeviceContext->IrpCompletionQueue,
452: &Request->IoRequestPacket->Tail.Overlay.ListEntry);
453:
454: } else {
455:
456: IoCompleteRequest (Request->IoRequestPacket, IO_NETWORK_INCREMENT);
457:
458: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
459:
460: }
461:
462: //
463: // Put the request back on the free list. NOTE: we have the
464: // lock held here.
465: //
466:
467:
468: DeviceContext->RequestTotal += DeviceContext->RequestInUse;
469: ++DeviceContext->RequestSamples;
470: --DeviceContext->RequestInUse;
471:
472: if ((DeviceContext->RequestAllocated - DeviceContext->RequestInUse) >
473: DeviceContext->RequestInitAllocated) {
474: StDeallocateRequest (DeviceContext, Request);
475: } else {
476: InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
477: }
478:
479: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
480:
481: } /* StDestroyRequest */
482:
483:
484: VOID
485: StRefRequest(
486: IN PTP_REQUEST Request
487: )
488:
489: /*++
490:
491: Routine Description:
492:
493: This routine increments the reference count on a transport request.
494:
495: Arguments:
496:
497: Request - Pointer to a TP_REQUEST block.
498:
499: Return Value:
500:
501: none.
502:
503: --*/
504:
505: {
506: INTERLOCKED_RESULT result;
507:
508: ASSERT (Request->ReferenceCount > 0);
509:
510: result = ExInterlockedIncrementLong (
511: &Request->ReferenceCount,
512: Request->ProviderInterlock);
513:
514: } /* StRefRequest */
515:
516:
517: VOID
518: StDerefRequest(
519: IN PTP_REQUEST Request
520: )
521:
522: /*++
523:
524: Routine Description:
525:
526: This routine dereferences a transport request by decrementing the
527: reference count contained in the structure. If, after being
528: decremented, the reference count is zero, then this routine calls
529: StDestroyRequest to remove it from the system.
530:
531: Arguments:
532:
533: Request - Pointer to a transport request object.
534:
535: Return Value:
536:
537: none.
538:
539: --*/
540:
541: {
542: INTERLOCKED_RESULT result;
543:
544: result = ExInterlockedDecrementLong (
545: &Request->ReferenceCount,
546: Request->ProviderInterlock);
547:
548: ASSERT (result != ResultNegative);
549:
550: //
551: // If we have deleted all references to this request, then we can
552: // destroy the object. It is okay to have already released the spin
553: // lock at this point because there is no possible way that another
554: // stream of execution has access to the request any longer.
555: //
556:
557: if (result == ResultZero) {
558: StDestroyRequest (Request);
559: }
560:
561: } /* StDerefRequest */
562:
563:
564: VOID
565: StCompleteRequest(
566: IN PTP_REQUEST Request,
567: IN NTSTATUS Status,
568: IN ULONG Information
569: )
570:
571: /*++
572:
573: Routine Description:
574:
575: This routine completes a transport request object, completing the I/O,
576: stopping the timeout, and freeing up the request object itself.
577:
578: Arguments:
579:
580: Request - Pointer to a transport request object.
581:
582: Status - Actual return status to be assigned to the request. This
583: value may be overridden if the timed-out bitflag is set in the request.
584:
585: Information - the information field for the I/O Status Block.
586:
587: Return Value:
588:
589: none.
590:
591: --*/
592:
593: {
594: KIRQL oldirql;
595: PIRP Irp;
596: NTSTATUS FinalStatus = Status;
597: BOOLEAN TimerWasSet;
598:
599: ASSERT (Status != STATUS_PENDING);
600:
601: if (Request->Flags & REQUEST_FLAGS_SEND_RCV) {
602:
603: //
604: // Sends and receives we check for since we know
605: // they don't have timers and should only complete
606: // once.
607: //
608:
609: Request->Flags |= REQUEST_FLAGS_STOPPING;
610: Irp = Request->IoRequestPacket;
611: Irp->IoStatus.Status = FinalStatus;
612: Irp->IoStatus.Information = Information;
613:
614: StDereferenceRequest ("Complete", Request); // remove creation reference.
615: return;
616: }
617:
618:
619: ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
620:
621: if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
622: Request->Flags |= REQUEST_FLAGS_STOPPING;
623:
624: //
625: // Cancel the pending timeout on this request. Not all requests
626: // have their timer set. If this request has the TIMER bit set,
627: // then the timer needs to be cancelled. If it cannot be cancelled,
628: // then the timer routine will be run, so we just return and let
629: // the timer routine worry about cleaning up this request.
630: //
631:
632: if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) {
633: Request->Flags &= ~REQUEST_FLAGS_TIMER;
634: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
635: TimerWasSet = KeCancelTimer (&Request->Timer);
636:
637: if (TimerWasSet) {
638: StDereferenceRequest ("Complete: stop timer", Request);
639: }
640:
641: } else {
642: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
643: }
644:
645: Irp = Request->IoRequestPacket;
646:
647:
648: //
649: // Install the return code in the IRP so that when we call StDestroyRequest,
650: // it will get completed with the proper return status.
651: //
652:
653: Irp->IoStatus.Status = FinalStatus;
654: Irp->IoStatus.Information = Information;
655:
656: //
657: // The entire transport is done with this request.
658: //
659:
660: StDereferenceRequest ("Complete", Request); // remove creation reference.
661:
662: } else {
663:
664: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
665:
666: }
667:
668: } /* StCompleteRequest */
669:
670:
671: VOID
672: StRefSendIrp(
673: IN PIO_STACK_LOCATION IrpSp
674: )
675:
676: /*++
677:
678: Routine Description:
679:
680: This routine increments the reference count on a send IRP.
681:
682: Arguments:
683:
684: IrpSp - Pointer to the IRP's stack location.
685:
686: Return Value:
687:
688: none.
689:
690: --*/
691:
692: {
693: INTERLOCKED_RESULT result;
694:
695: ASSERT (IRP_REFCOUNT(IrpSp) > 0);
696:
697: result = ExInterlockedIncrementLong (
698: &IRP_REFCOUNT(IrpSp),
699: &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock));
700:
701: } /* StRefSendIrp */
702:
703:
704: VOID
705: StDerefSendIrp(
706: IN PIO_STACK_LOCATION IrpSp
707: )
708:
709: /*++
710:
711: Routine Description:
712:
713: This routine dereferences a transport send IRP by decrementing the
714: reference count contained in the structure. If, after being
715: decremented, the reference count is zero, then this routine calls
716: IoCompleteRequest to actually complete the IRP.
717:
718: NOTE: This assume that IRP_CONNECTION(IrpSp) has been changed
719: to point to the IRP instead of the connection.
720:
721: Arguments:
722:
723: Request - Pointer to a transport send IRP's stack location.
724:
725: Return Value:
726:
727: none.
728:
729: --*/
730:
731: {
732: INTERLOCKED_RESULT result;
733:
734: result = ExInterlockedDecrementLong (
735: &IRP_REFCOUNT(IrpSp),
736: &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock));
737:
738: ASSERT (result != ResultNegative);
739:
740: //
741: // If we have deleted all references to this request, then we can
742: // destroy the object. It is okay to have already released the spin
743: // lock at this point because there is no possible way that another
744: // stream of execution has access to the request any longer.
745: //
746:
747: if (result == ResultZero) {
748:
749: PIRP Irp = (PIRP)IRP_CONNECTION(IrpSp);
750:
751: IRP_REFCOUNT(IrpSp) = 0;
752: IRP_CONNECTION (IrpSp) = NULL;
753:
754: IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
755:
756: }
757:
758: } /* StDerefSendIrp */
759:
760:
761: VOID
762: StCompleteSendIrp(
763: IN PIRP Irp,
764: IN NTSTATUS Status,
765: IN ULONG Information
766: )
767:
768: /*++
769:
770: Routine Description:
771:
772: This routine completes a transport send IRP.
773:
774: Arguments:
775:
776: Irp - Pointer to a send IRP.
777:
778: Status - Actual return status to be assigned to the request. This
779: value may be overridden if the timed-out bitflag is set in the request.
780:
781: Information - the information field for the I/O Status Block.
782:
783: Return Value:
784:
785: none.
786:
787: --*/
788:
789: {
790: PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
791: PTP_CONNECTION Connection;
792:
793: ASSERT (Status != STATUS_PENDING);
794:
795: Connection = IRP_CONNECTION(IrpSp);
796:
797:
798: //
799: // Sends and receives we check for since we know
800: // they don't have timers and should only complete
801: // once.
802: //
803:
804: Irp->IoStatus.Status = Status;
805: Irp->IoStatus.Information = Information;
806:
807: IRP_CONNECTION(IrpSp) = Irp;
808:
809: StDereferenceSendIrp ("Complete", IrpSp); // remove creation reference.
810:
811: StDereferenceConnection ("Removing Connection", Connection);
812:
813: } /* StCompleteSendIrp */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.