1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxRequestBase.hpp
8 
9 Abstract:
10 
11     This is the base class which request objects derive from for the driver
12     frameworks.
13 
14     The request base object wraps the IRP, containing persistent
15     information required by the driver frameworks.
16 
17 Author:
18 
19 
20 
21 
22 Environment:
23 
24     Both kernel and user mode
25 
26 Revision History:
27 
28 --*/
29 
30 #ifndef _FXREQUESTBASE_H_
31 #define _FXREQUESTBASE_H_
32 
33 #include "fxrequestcallbacks.hpp"
34 
35 #define WDF_REQUEST_REUSE_MUST_COMPLETE 2
36 
37 
38 //
39 // COMPLETED - set when the request's i/o completion routine has executed
40 //
41 // PENDED - set when the request has been put onto the target's CSQ
42 //
43 // TIMER_SET - set when a timer has been queued along with sending the request
44 //             down to the target
45 //
46 // CANCELLED_FROM_TIME - set by the timer to indicate that the request was
47 //                       cancelled by the timer DPC
48 //
49 // IGNORE_STATE - set when the request is going to be sent ignoring the
50 //                state of the target.
51 //
52 enum FxRequestTargetFlags {
53     FX_REQUEST_COMPLETED                = 0x01,
54     FX_REQUEST_PENDED                   = 0x02,
55     FX_REQUEST_TIMER_SET                = 0x04,
56     FX_REQUEST_CANCELLED_FROM_TIMER     = 0x08,
57     FX_REQUEST_IGNORE_STATE             = 0x10,
58 };
59 
60 //
61 // internal private constraints
62 //
63 #define WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND (0x80000000)
64 
65 #define WDF_REQUEST_INTERNAL_CONSTRAINTS_VALID_FLAGS \
66     (WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND)
67 
68 
69 //
70 // Completion event callback prototype
71 //
72 typedef
73 VOID
74 (*PFN_COMPLETE_COPY_ROUTINE)(
75     __in FxIoTarget* This,
76     __in FxRequest* Request,
77     __in_opt FxRequestContext* Context
78     );
79 
80 
81 struct FxRequestTimer : public FxStump {
82     MxTimer Timer;
83 };
84 
85 enum FxRequestAllocationSource {
86     REQUEST_ALLOCATED_FROM_IO = 0,  // Irp came from the I/O package
87     REQUEST_ALLOCATED_INTERNAL = 1, // Irp was allocated internally and should be freed by the request
88     REQUEST_ALLOCATED_DRIVER = 2,   // Irp was given to the request by the driver writer
89 };
90 
91 enum FxRequestIrpOwnership {
92     FxRequestOwnsIrp = 1,
93     FxRequestDoesNotOwnIrp,
94 };
95 
96 // begin_wpp config
97 // CUSTOM_TYPE(FxRequestIrpOwnership, ItemEnum(FxRequestIrpOwnership));
98 // end_wpp
99 
100 enum FxRequestConstructorCaller {
101     FxRequestConstructorCallerIsFx = 1,
102     FxRequestConstructorCallerIsDriver,
103 };
104 
105 //
106 // These defines are for VerifierFlags
107 //
108 enum FxRequestVerifierFlags {
109     // Request has been passed to the Driver
110     FXREQUEST_FLAG_DRIVER_OWNED             = 0x0001,
111 
112     // Request was returned as a "Tag" request to WdfIoQueuePeekNextRequest.
113     FXREQUEST_FLAG_TAG_REQUEST              = 0x0002,
114 
115     // Request has been forwarded from one queue to another
116     FXREQUEST_FLAG_FORWARDED                = 0x0004,
117 
118     // Request is being EvtIoDefault to the driver
119     FXREQUEST_FLAG_DRIVER_DISPATCH          = 0x0008,
120 
121     // The driver has specified the request as cancelable
122     FXREQUEST_FLAG_DRIVER_CANCELABLE        = 0x0010,
123 
124     FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT = 0x0020,
125 
126     // The request has been cancelled
127     FXREQUEST_FLAG_CANCELLED                = 0x0040,
128 
129     // the next stack location has been formatted
130     FXREQUEST_FLAG_FORMATTED                = 0x0080,
131 
132     // the request has been sent on an I/O target and is in the target's sent list
133     FXREQUEST_FLAG_SENT_TO_TARGET           = 0x0100,
134 
135     // used to make sure the driver stop acknowledges in the context of EvtIoStop
136     FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT = 0x0200,
137 
138     // used to indicate whether the Reserved Request is in use or on Free list
139     FXREQUEST_FLAG_RESERVED_REQUEST_ASSOCIATED_WITH_IRP = 0x0400,
140 };
141 
142 enum FxRequestBaseFlags {
143     FxRequestBaseSystemMdlMapped  = 0x1,
144     FxRequestBaseOutputMdlMapped  = 0x2,
145     FxRequestBaseSyncCleanupContext = 0x10,
146 };
147 
148 enum FxRequestBaseStaticFlags {
149     FxRequestBaseStaticSystemBufferValid  = 0x1,
150     FxRequestBaseStaticOutputBufferValid  = 0x2,
151 };
152 
153 //
154 // Designed to fit into a byte.  FxRequestCompletionPkgFlag is a bit value
155 // used to distinguish between calling back into the io package or the current
156 // queue.  When calling back into the current queue, we assume m_IoQueue is valid
157 //
158 enum FxRequestCompletionState {
159     FxRequestCompletionStateIoPkgFlag = 0x80,
160 
161     FxRequestCompletionStateNone  = 0x00,
162     FxRequestCompletionStateQueue = 0x01,
163     FxRequestCompletionStateIoPkg = 0x02 | FxRequestCompletionStateIoPkgFlag,
164 };
165 
166 class FxRequestBase : public FxNonPagedObject {
167 
168     friend FxIoTarget;
169     friend FxSyncRequest;
170 
171 public:
172 
173     __inline
174     VOID
175     SetCompletionRoutine(
176         __in_opt PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine = NULL,
177         __in_opt WDFCONTEXT CompletionContext = NULL
178         )
179     {
180         m_CompletionRoutine.m_Completion = CompletionRoutine;
181         m_TargetCompletionContext = CompletionContext;
182     }
183 
184     PFN_WDF_REQUEST_COMPLETION_ROUTINE
185     ClearCompletionRoutine(
186         VOID
187         )
188     {
189         PFN_WDF_REQUEST_COMPLETION_ROUTINE pRoutine;
190 
191         pRoutine = m_CompletionRoutine.m_Completion;
192         m_CompletionRoutine.m_Completion = NULL;
193 
194         return pRoutine;
195     }
196 
197     WDFCONTEXT
198     ClearCompletionContext(
199         VOID
200         )
201     {
202         WDFCONTEXT pContext;
203 
204         pContext = m_TargetCompletionContext;
205         m_TargetCompletionContext = NULL;
206 
207         return pContext;
208     }
209 
210     __inline
211     BOOLEAN
212     IsCompletionRoutineSet(
213         VOID
214         )
215     {
216         return (m_CompletionRoutine.m_Completion != NULL) ?
217                     TRUE : FALSE;
218     }
219 
220     __inline
221     BOOLEAN
222     IsCancelRoutineSet(
223         VOID
224         )
225     {
226         return (m_CancelRoutine.m_Cancel != NULL) ?
227                     TRUE : FALSE;
228     }
229 
230     __inline
231     FxRequestContext*
232     GetContext(
233         VOID
234         )
235     {
236         return m_RequestContext;
237     }
238 
239     __inline
240     VOID
241     SetContext(
242         __in FxRequestContext* RequestContext = NULL
243         )
244     {
245         //
246         // If we are setting to the same value, just return
247         //
248         if (m_RequestContext == RequestContext) {
249             return;
250         }
251 
252         //
253         // If we are changing the context to another unique pointer, free the
254         // old context.
255         //
256         if (m_RequestContext != NULL) {
257             delete m_RequestContext;
258         }
259 
260         m_RequestContext = RequestContext;
261     }
262 
263     VOID
264     ContextReleaseAndRestore(
265         VOID
266         )
267     {
268         //
269         // This does not free the context, rather it tells the context to release
270         // any references it is holding and restore fields back into the PIRP
271         //
272         if (m_RequestContext != NULL && m_Irp.GetIrp() != NULL) {
273             m_RequestContext->ReleaseAndRestore(this);
274             VerifierClearFormatted();
275         }
276     }
277 
278     __inline
279     VOID
280     EnableContextDisposeNotification(
281         VOID
282         )
283     {
284         MarkDisposeOverride();
285     }
286 
287     __inline
288     BOOLEAN
289     HasContextType(
290         __in FX_REQUEST_CONTEXT_TYPE Type
291         )
292     {
293         return (m_RequestContext != NULL &&
294                 m_RequestContext->m_RequestType == Type) ? TRUE : FALSE;
295     }
296 
297     __inline
298     BOOLEAN
299     HasContext(
300         VOID
301         )
302     {
303         return (m_RequestContext != NULL &&
304                 m_RequestContext->m_RequestType !=
305                     FX_REQUEST_CONTEXT_TYPE_NONE) ? TRUE : FALSE;
306     }
307 
308     __inline
309     MdIrp
310     GetSubmitIrp(
311         VOID
312         )
313     {
314         return m_Irp.GetIrp();
315     }
316 
317     __inline
318     FxIrp*
319     GetSubmitFxIrp(
320         VOID
321         )
322     {
323         return &m_Irp;
324     }
325 
326     MdIrp
327     SetSubmitIrp(
328         __in_opt MdIrp NewIrp,
329         __in BOOLEAN FreeIrp = TRUE
330         );
331 
332     __inline
333     BOOLEAN
334     CanComplete(
335         VOID
336         )
337     {
338         LONG count;
339         count = InterlockedDecrement(&m_IrpCompletionReferenceCount);
340         ASSERT(count >= 0);
341         return count == 0 ? TRUE : FALSE;
342     }
343 
344     VOID
345     CompleteSubmitted(
346         VOID
347         );
348 
349     _Must_inspect_result_
350     NTSTATUS
351     ValidateTarget(
352         __in FxIoTarget* Target
353         );
354 
355     __inline
356     FxIoTarget*
357     GetTarget(
358         VOID
359         )
360     {
361         return m_Target;
362     }
363 
364     VOID
365     __inline
366     SetTarget(
367         __in FxIoTarget* Target
368         )
369     {
370         m_Target = Target;
371     }
372 
373     __inline
374     UCHAR
375     GetTargetFlags(
376         VOID
377         )
378     {
379         // Assumes caller is holding appropriate lock
380         return m_TargetFlags;
381     }
382 
383     __inline
384     VOID
385     SetTargetFlags(
386         __in UCHAR Flags
387         )
388     {
389         // Assumes caller is holding appropriate lock
390         m_TargetFlags |= Flags;
391     }
392 
393     __inline
394     ULONG
395     ClearTargetFlags(
396         __in UCHAR Flags
397         )
398     {
399         ULONG oldFlags;
400 
401         oldFlags = m_TargetFlags;
402 
403         // Assumes caller is holding appropriate lock
404         m_TargetFlags &= ~Flags;
405 
406         return oldFlags;
407     }
408 
409     __inline
410     VOID
411     SetRequestBaseFlags(
412         __in UCHAR Flags
413         )
414     {
415         // Assumes caller is holding appropriate lock
416         m_RequestBaseFlags|= Flags;
417     }
418 
419     SHORT
420     GetVerifierFlagsLocked(
421         VOID
422         )
423     {
424         ASSERT(GetDriverGlobals()->FxVerifierOn);
425         return m_VerifierFlags;
426     }
427 
428     __inline
429     SHORT
430     GetVerifierFlags(
431         VOID
432         )
433     {
434         SHORT flags;
435         KIRQL irql;
436 
437         Lock(&irql);
438         flags =  GetVerifierFlagsLocked();
439         Unlock(irql);
440 
441         return flags;
442     }
443 
444     __inline
445     VOID
446     SetVerifierFlagsLocked(
447         __in SHORT Flags
448         )
449     {
450         m_VerifierFlags |= Flags;
451     }
452 
453     __inline
454     VOID
455     SetVerifierFlags(
456         __in SHORT Flags
457         )
458     {
459         KIRQL irql;
460 
461         ASSERT(GetDriverGlobals()->FxVerifierOn);
462 
463         Lock(&irql);
464         SetVerifierFlagsLocked(Flags);
465         Unlock(irql);
466     }
467 
468     __inline
469     VOID
470     ClearVerifierFlagsLocked(
471         __in SHORT Flags
472         )
473     {
474         m_VerifierFlags &= ~Flags;
475     }
476 
477     __inline
478     VOID
479     ClearVerifierFlags(
480         __in SHORT Flags
481         )
482     {
483         KIRQL irql;
484 
485         ASSERT(GetDriverGlobals()->FxVerifierOn);
486 
487         Lock(&irql);
488         ClearVerifierFlagsLocked(Flags);
489         Unlock(irql);
490     }
491 
492     __inline
493     VOID
494     VerifierSetFormatted(
495         VOID
496         )
497     {
498         if (GetDriverGlobals()->FxVerifierOn &&
499             GetDriverGlobals()->FxVerifierIO) {
500             SetVerifierFlags(FXREQUEST_FLAG_FORMATTED);
501         }
502     }
503 
504     __inline
505     VOID
506     VerifierClearFormatted(
507         VOID
508         )
509     {
510         if (GetDriverGlobals()->FxVerifierOn &&
511             GetDriverGlobals()->FxVerifierIO) {
512             ClearVerifierFlags(FXREQUEST_FLAG_FORMATTED);
513         }
514     }
515 
516     __inline
517     BOOLEAN
518     VerifierIsFormatted(
519         VOID
520         )
521     {
522         if (GetDriverGlobals()->FxVerifierOn &&
523             GetDriverGlobals()->FxVerifierIO) {
524             return (GetVerifierFlags() & FXREQUEST_FLAG_FORMATTED) ? TRUE : FALSE;
525         }
526         else {
527             //
528             // we are not tracking the state
529             //
530             return TRUE;
531         }
532     }
533 
534     __inline
535     BOOLEAN
536     ShouldClearContext(
537         VOID
538         )
539     {
540         return (m_RequestBaseFlags & FxRequestBaseSyncCleanupContext) ? TRUE
541                                                                       : FALSE;
542     }
543 
544     _Must_inspect_result_
545     NTSTATUS
546     CreateTimer(
547         VOID
548         );
549 
550     VOID
551     StartTimer(
552         __in LONGLONG Timeout
553         );
554 
555     _Must_inspect_result_
556     BOOLEAN
557     CancelTimer(
558         VOID
559         );
560 
561     BOOLEAN
562     Cancel(
563         VOID
564         );
565 
566     BOOLEAN
567     __inline
568     IsAllocatedFromIo(
569         VOID
570         )
571     {
572         return m_IrpAllocation == REQUEST_ALLOCATED_FROM_IO ? TRUE : FALSE;
573     }
574 
575     BOOLEAN
576     __inline
577     IsAllocatedDriver(
578         VOID
579         )
580     {
581         return m_IrpAllocation == REQUEST_ALLOCATED_DRIVER ? TRUE : FALSE;
582     }
583 
584     BOOLEAN
585     __inline
586     IsCanComplete(
587         VOID
588         )
589     {
590         return m_CanComplete;
591     }
592 
593     __inline
594     VOID
595     SetCompleted(
596         __in BOOLEAN Value
597         )
598     {
599         m_Completed = Value;
600     }
601 
602     VOID
603     __inline
604     SetPriorityBoost(
605         CCHAR PriorityBoost
606         )
607     {
608         m_PriorityBoost = PriorityBoost;
609     }
610 
611     CCHAR
612     __inline
613     GetPriorityBoost(
614         VOID
615         )
616     {
617         return m_PriorityBoost;
618     }
619 
620 
621 
622 
623 
624 
625 
626 
627 
628 
629 
630 
631 
632 
633     __inline
634     WDFREQUEST
635     GetHandle(
636         VOID
637         )
638     {
639         return (WDFREQUEST) GetObjectHandle();
640     }
641 
642     __inline
643     static
644     FxRequestBase*
645     _FromListEntry(
646         __in PLIST_ENTRY Entry
647         )
648     {
649         return CONTAINING_RECORD(Entry, FxRequestBase, m_ListEntry);
650     }
651 
652     __inline
653     static
654     FxRequestBase*
655     _FromDrainEntry(
656         __in PSINGLE_LIST_ENTRY Entry
657         )
658     {
659         return CONTAINING_RECORD(Entry, FxRequestBase, m_DrainSingleEntry);
660     }
661 
662 
663     __inline
664     static
665     FxRequestBase*
666     _FromCsqContext(
667         __in PMdIoCsqIrpContext Context
668         )
669     {
670         return CONTAINING_RECORD(Context, FxRequestBase, m_CsqContext);
671     }
672 
673     __inline
674     PVOID
675     GetTraceObjectHandle(
676         VOID
677         )
678     {
679         PVOID handle;
680 
681         handle = GetObjectHandle();
682 
683         if (handle != NULL) {
684             return handle;
685         }
686         else {
687             return (PVOID) this;
688         }
689     }
690 
691     VOID
692     FreeMdls(
693         VOID
694     );
695 
696     DECLSPEC_NORETURN
697     VOID
698     FatalError(
699         __in NTSTATUS Status
700         );
701 
702     VOID
703     ClearFieldsForReuse(
704         VOID
705         );
706 
707 protected:
708     FxRequestBase(
709         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
710         __in USHORT ObjectSize,
711         __in_opt MdIrp Irp,
712         __in FxRequestIrpOwnership Ownership,
713         __in FxRequestConstructorCaller Caller,
714         __in FxObjectType ObjectType = FxObjectTypeExternal
715         );
716 
717     virtual
718     ~FxRequestBase(
719         VOID
720         );
721 
722     // Do not specify argument names
723     FX_DECLARE_VF_FUNCTION(
724     VOID,
725     VerifyDispose
726         );
727 
728     // FxObject overrides
729     virtual
730     BOOLEAN
731     Dispose(
732         VOID
733         );
734 
735     static
736     MdDeferredRoutineType _TimerDPC;
737 
738     VOID
739     CompleteSubmittedNoContext(
740         VOID
741         );
742 
743     VOID
744     ZeroOutDriverContext(
745         VOID
746         )
747     {
748 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
749     RtlZeroMemory(GetSubmitFxIrp()->GetDriverContext(),
750                   GetSubmitFxIrp()->GetDriverContextSize());
751 #else
752     //
753     // UMDF host doesn't expose any easier way to zero out the contexts so
754     // set context to NULL one by one.
755     //
756     GetSubmitFxIrp()->SetContext(0, NULL);
757     GetSubmitFxIrp()->SetContext(1, NULL);
758     GetSubmitFxIrp()->SetContext(2, NULL);
759     GetSubmitFxIrp()->SetContext(3, NULL);
760 #endif
761     }
762 
763 public:
764 
765     union {
766         //
767         // The cancel safe queues use this context to identify
768         // the request in a race free manner.
769         //
770         MdIoCsqIrpContext m_CsqContext;
771 
772         //
773         // IoTargets uses this to track the request when it is sent to the target.
774         // Since the request cannot be on an CSQ and sent to a target at the
775         // same time, we can unionize this with the CSQ context.
776         //
777         LIST_ENTRY   m_ListEntry;
778     };
779 
780     union {
781         //
782         // IoTargest uses this when it needs to create a list of requests to cancel
783         // when making a state transition
784         //
785         SINGLE_LIST_ENTRY m_DrainSingleEntry;
786 
787         //
788         // If TRUE, the driver formatted the request by copying the current stack
789         // location to next or by manually passing in an IO_STACK_LOCATION.  This
790         // is union'ed with m_DrainSingleEntry b/c it is only relevant during
791         // send and forget and the request is never enqueued on the target in
792         // this case and m_DrainSingleEntry is used when tracking requests sent
793         // on a target for cancelation due to a target state change.
794         //
795         BOOLEAN m_NextStackLocationFormatted;
796     };
797 
798 protected:
799     //
800     // The NT IRP is wrapped by a frameworks FxIrp
801     //
802     // Note: If m_Irp is NULL after initialization, this means
803     //       the IRP was cancelled by a FxIrpQueue cancellation
804     //       callback, or completed.
805     //
806     FxIrp              m_Irp;
807 
808     //
809     // Target of the request.  Access to this field is unguarded.  The following
810     // have access to this field
811     // o The owning target itself
812     // o _TimerDPC()
813     // o Cancel() IFF it has successfully incremented the irp completion ref count
814     //
815     FxIoTarget* m_Target;
816 
817     FxRequestContext* m_RequestContext;
818 
819 
820 
821 
822     FxRequestTimer* m_Timer;
823 
824     //
825     // Client driver completion routine to call when the request has come back
826     // from the target device.
827     //
828     FxRequestCancelCallback m_CancelRoutine;
829 
830     FxRequestCompletionCallback m_CompletionRoutine;
831 
832     //
833     // Context to pass to CompletionRoutine when called
834     //
835     WDFCONTEXT m_TargetCompletionContext;
836 
837     //
838     // Synchronization for this field is through Interlocked operations
839     //
840     LONG m_IrpCompletionReferenceCount;
841 
842     //
843     // Access to flags guarded by FxIoTarget::Lock
844     //
845     // Values defined in the enum FxRequestTargetFlags
846     //
847     union {
848         UCHAR m_TargetFlags;
849 
850         //
851         // These are used purely for debugging, not in live code anywhere!
852         // NOTE:  if FxRequestTargetFlagschanges, so this this union
853         //
854         struct {
855             UCHAR Completed : 1;
856             UCHAR FlagsPended : 1;
857             UCHAR TimerSet : 1;
858             UCHAR CancelledFromTimer : 1;
859             UCHAR IgnoreState : 1;
860         } m_TargetFlagsByName;
861     };
862 
863     //
864     // Contains a value from the enum type FxRequestAllocationSource describing
865     // how the irp was allocated
866     //
867     UCHAR m_IrpAllocation;
868 
869     BOOLEAN m_Completed;
870 
871     BOOLEAN m_Canceled;
872 
873     WDFOBJECT_OFFSET_ALIGNED m_SystemBufferOffset;
874 
875     union {
876         //
877         // These are flags used by verifier.  Set with values from the enum
878         // FxRequestVerifierFlags
879         //
880         SHORT m_VerifierFlags;
881 
882         struct {
883             SHORT DriverOwned : 1;
884             SHORT TagRequest : 1;
885             SHORT Forwarded : 1;
886             SHORT DriverDispatch : 1;
887             SHORT DriverCancelable : 1;
888             SHORT DriverInprocessContext : 1;
889             SHORT Cancelled : 1;
890             SHORT Formatted : 1;
891             SHORT SentToTarget : 1;
892             SHORT DriverInEvtIoStopContext : 1;
893         } m_VeriferFlagsByName;
894     };
895 
896     //
897     // If this is !=0, its an indication of outstanding references
898     // on WDM IRP fields such as any system buffers.
899     //
900     LONG m_IrpReferenceCount;
901 
902     // This field !=NULL if the request is on an IrpQueue.
903     FxIrpQueue*        m_IrpQueue;
904 
905     WDFOBJECT_OFFSET_ALIGNED m_OutputBufferOffset;
906 
907     union {
908         //
909         // Bit field.  Set with values from the enum FxRequestBaseFlags
910         //
911         UCHAR m_RequestBaseFlags;
912 
913         struct {
914             UCHAR SystemMdlMapped : 1;
915             UCHAR OutputMdlMapped : 1;
916             UCHAR SyncCleanupContext : 1;
917         } m_RequestBaseFlagsByName;
918     };
919 
920     union {
921         //
922         // Bit field.  Set with values from the enum FxRequestBaseStaticFlags
923         //
924 
925         //
926         UCHAR m_RequestBaseStaticFlags;
927 
928         struct {
929             UCHAR SystemBufferValid  : 1;
930             UCHAR OutputBufferValid  : 1;
931         } m_RequestBaseStaticFlagsByName;
932     };
933 
934     //
935     // Priority boost.
936     //
937     CCHAR m_PriorityBoost;
938 
939     //
940     // Contains values from FxRequestCompletionState
941     //
942     BYTE m_CompletionState;
943 
944     //
945     // TRUE, request can be completed by the driver.
946     //
947     BOOLEAN m_CanComplete;
948 
949     //
950     // If !=NULL, MDL allocated and assocated with the request
951     //
952     PMDL m_AllocatedMdl;
953 };
954 
955 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
956 #include "fxrequestbasekm.hpp"
957 #elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE))
958 #include "fxrequestbaseum.hpp"
959 #endif
960 
961 
962 #endif // _FXREQUESTBASE_H_
963