/***************************************************************************

Copyright (c) 1999  Microsoft Corporation

Module Name:

    RNDISMP.H

Abstract:

    Header file for Remote NDIS Miniport driver. Sits on top of Remote 
    NDIS bus specific layers.

Environment:

    kernel mode only

Notes:

    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
    PURPOSE.

    Copyright (c) 1999 Microsoft Corporation.  All Rights Reserved.


Revision History:

    5/6/99 : created

Author:

    Tom Green

    
****************************************************************************/

#ifndef _RNDISMP_H_
#define _RNDISMP_H_

#ifndef OID_GEN_RNDIS_CONFIG_PARAMETER
#define OID_GEN_RNDIS_CONFIG_PARAMETER          0x0001021B  // Set only
#endif


//
// DEBUG stuff
//

#if DBG


//
// Definitions for all of the Debug macros.  If we're in a debug (DBG) mode,
// these macros will print information to the debug terminal.  If the
// driver is compiled in a free (non-debug) environment the macros become
// NOPs.
//

VOID
NTAPI
DbgBreakPoint(VOID);

//
// DEBUG enable bit definitions
//
#define DBG_LEVEL0          0x1000      // Display TRACE0 messages
#define DBG_LEVEL1          0x0001      // Display TRACE1 messages
#define DBG_LEVEL2          0x0002      // Display TRACE2 messages
#define DBG_LEVEL3          0x0004      // Display TRACE3 messages
#define DBG_OID_LIST        0x0008      // display OID list
#define DBG_OID_NAME        0x0010      // display name of OID in query and set routines
#define DBG_DUMP            0x0020      // Display buffer dumps
#define DBG_LOG_SENDS       0x0100      // Log sent messages.

#define TRACE0(S)     {if(RndismpDebugFlags & DBG_LEVEL0) {DbgPrint("RNDISMP: "); DbgPrint S;}}
#define TRACE1(S)     {if(RndismpDebugFlags & DBG_LEVEL1) {DbgPrint("RNDISMP: "); DbgPrint S;}}
#define TRACE2(S)     {if(RndismpDebugFlags & DBG_LEVEL2) {DbgPrint("RNDISMP: "); DbgPrint S;}}
#define TRACE3(S)     {if(RndismpDebugFlags & DBG_LEVEL3) {DbgPrint("RNDISMP: "); DbgPrint S;}}

#define TRACEDUMP(_s, _buf, _len)     {if(RndismpDebugFlags & DBG_DUMP) {DbgPrint("RNDISMP: "); DbgPrint _s; RndisPrintHexDump(_buf, _len);}}

#define DISPLAY_OID_LIST(Adapter)   DisplayOidList(Adapter)

#define GET_OID_NAME(Oid)           GetOidName(Oid)

#define OID_NAME_TRACE(Oid, s)                                 \
{                                                               \
    if(RndismpDebugFlags & DBG_OID_NAME)                        \
        DbgPrint("RNDISMP: %s: (%s)  (%08X)\n", s, GET_OID_NAME(Oid), Oid);     \
}

#undef ASSERT
#define ASSERT(exp)                                             \
{                                                               \
    if(!(exp))                                                  \
    {                                                           \
        DbgPrint("Assertion Failed: %s:%d %s\n",                \
                 __FILE__,__LINE__,#exp);                       \
        DbgBreakPoint();                                        \
    }                                                           \
}

#define DBGINT(S)                                               \
{                                                               \
    DbgPrint("%s:%d - ", __FILE__, __LINE__);                   \
    DbgPrint S;                                                 \
    DbgBreakPoint();                                            \
}


// check frame for problems
#define CHECK_VALID_FRAME(Frame)                                \
{                                                               \
    ASSERT(Frame);                                              \
    if(Frame)                                                   \
    {                                                           \
        if(Frame->Signature != FRAME_SIGNATURE)                 \
        {                                                       \
            DbgPrint("RNDISMP: Invalid Frame (%p) Signature: %s:%d\n",\
                    Frame, __FILE__,__LINE__);                  \
            DbgBreakPoint();                                    \
        }                                                       \
    }                                                           \
}

// check adapter for problems
#define CHECK_VALID_ADAPTER(Adapter)                            \
{                                                               \
    ASSERT(Adapter);                                            \
    if(Adapter)                                                 \
    {                                                           \
        if(Adapter->Signature != ADAPTER_SIGNATURE)             \
        {                                                       \
            DbgPrint("RNDISMP: Invalid Adapter Signature: %s:%d\n",\
                     __FILE__,__LINE__);                        \
            DbgBreakPoint();                                    \
        }                                                       \
    }                                                           \
}

// check block for problems
#define CHECK_VALID_BLOCK(Block)                                \
{                                                               \
    ASSERT(Block);                                              \
    if(Block)                                                   \
    {                                                           \
        if(Block->Signature != BLOCK_SIGNATURE)                 \
        {                                                       \
            DbgPrint("RNDISMP: Invalid Block Signature: %s:%d\n",\
                     __FILE__,__LINE__);                        \
            DbgBreakPoint();                                    \
        }                                                       \
    }                                                           \
}


#define RNDISMP_ASSERT_AT_PASSIVE()                             \
{                                                               \
    KIRQL Irql = KeGetCurrentIrql();                            \
    if (Irql != PASSIVE_LEVEL)                                  \
    {                                                           \
        DbgPrint("RNDISMP: found IRQL %d instead of passive!\n", Irql); \
        DbgPrint("RNDISMP: at line %d, file %s\n", __LINE__, __FILE__); \
        DbgBreakPoint();                                        \
    }                                                           \
}


#define RNDISMP_ASSERT_AT_DISPATCH()                            \
{                                                               \
    KIRQL Irql = KeGetCurrentIrql();                            \
    if (Irql != DISPATCH_LEVEL)                                 \
    {                                                           \
        DbgPrint("RNDISMP: found IRQL %d instead of dispatch!\n", Irql); \
        DbgPrint("RNDISMP: at line %d, file %s\n", __LINE__, __FILE__); \
        DbgBreakPoint();                                        \
    }                                                           \
}


#define DBG_LOG_SEND_MSG(_pAdapter, _pMsgFrame)                 \
{                                                               \
    if (RndismpDebugFlags & DBG_LOG_SENDS)                      \
    {                                                           \
        RndisLogSendMessage(_pAdapter, _pMsgFrame);             \
    }                                                           \
}

#else // !DBG


#define TRACE0(S)
#define TRACE1(S)
#define TRACE2(S)
#define TRACE3(S)
#define TRACEDUMP(_s, _buf, _len)

#undef ASSERT
#define ASSERT(exp)

#define DBGINT(S)

#define CHECK_VALID_FRAME(Frame)
#define CHECK_VALID_ADAPTER(Adapter)
#define CHECK_VALID_BLOCK(Block)
#define DISPLAY_OID_LIST(Adapter)
#define OID_NAME_TRACE(Oid, s)

#define RNDISMP_ASSERT_AT_PASSIVE()
#define RNDISMP_ASSERT_AT_DISPATCH()

#define DBG_LOG_SEND_MSG(_pAdapter, _pMsgFrame)
#endif //DBG


//
// Defines
//

#define MINIMUM_ETHERNET_PACKET_SIZE            60
#define MAXIMUM_ETHERNET_PACKET_SIZE            1514
#define NUM_BYTES_PROTOCOL_RESERVED_SECTION     (4*sizeof(PVOID))
#define ETHERNET_HEADER_SIZE                    14

#define INITIAL_RECEIVE_FRAMES                  20
#define MAX_RECEIVE_FRAMES                      400

// this is the size of the buffer we will use to pass Data packet header data
// to the remote device.
#define RNDIS_PACKET_MESSAGE_HEADER_SIZE        128

// align all RNDIS packets on 4 byte boundaries
#define RNDIS_PACKET_MESSAGE_BOUNDARY           (4)

#define ONE_SECOND                              1000 // in milliseconds

#define KEEP_ALIVE_TIMER                        (5 * ONE_SECOND)

#define REQUEST_TIMEOUT                         (10 * ONE_SECOND)

#define FRAME_SIGNATURE                         ((ULONG)('GSRF'))
#define ADAPTER_SIGNATURE                       ((ULONG)('GSDA'))
#define BLOCK_SIGNATURE                         ((ULONG)('GSLB'))

#define RNDISMP_TAG_GEN_ALLOC                   ((ULONG)(' MNR'))
#define RNDISMP_TAG_SEND_FRAME                  ((ULONG)('sMNR'))
#define RNDISMP_TAG_RECV_DATA_FRAME             ((ULONG)('rMNR'))

#if DBG
#define MINIPORT_INIT_TIMEOUT                   (10 * ONE_SECOND)
#define MINIPORT_HALT_TIMEOUT                   (5 * ONE_SECOND)
#else
#define MINIPORT_INIT_TIMEOUT                   (5 * ONE_SECOND)
#define MINIPORT_HALT_TIMEOUT                   (2 * ONE_SECOND)
#endif

#ifndef MAX
#define MAX(a, b)   (((a) > (b)) ? (a) : (b))
#endif

// flags for driver and device supported OIDs
#define OID_NOT_SUPPORTED       0x0000
#define DRIVER_SUPPORTED_OID    0x0001
#define DEVICE_SUPPORTED_OID    0x0002


//
// Defines for OID_GEN_MAC_OPTIONS - most of the bits returned
// in response to this query are driver-specific, however some
// are device-specific.
//
#define RNDIS_DRIVER_MAC_OPTIONS        (NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA  | \
                                         NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |   \
                                         NDIS_MAC_OPTION_NO_LOOPBACK)

#define RNDIS_DEVICE_MAC_OPTIONS_MASK   NDIS_MAC_OPTION_8021P_PRIORITY

//
// Data structures
//

typedef NDIS_SPIN_LOCK          RNDISMP_SPIN_LOCK;


#ifdef BUILD_WIN9X

//
//  Equivalents of types defined for Win9X config mgr.
//
typedef ULONG           MY_CONFIGRET;
typedef ULONG           MY_DEVNODE;
typedef ULONG           MY_CONFIGFUNC;
typedef ULONG           MY_SUBCONFIGFUNC;
typedef MY_CONFIGRET    (_cdecl *MY_CMCONFIGHANDLER)(MY_CONFIGFUNC, MY_SUBCONFIGFUNC, MY_DEVNODE, ULONG, ULONG);

#define MY_CR_SUCCESS           0x00000000
#define MY_CONFIG_PREREMOVE     0x0000000C
#define MY_CONFIG_PRESHUTDOWN   0x00000012

#endif

//
// This structure contains information about a specific
// microport the miniport sits on top of. One of these
// per microport
//
typedef struct _DRIVER_BLOCK 
{
    // NDIS wrapper handle from NdisInitializeWrapper
    NDIS_HANDLE                 NdisWrapperHandle;

    // The NDIS version we manage to register this miniport instance as.
    UCHAR                       MajorNdisVersion;
    UCHAR                       MinorNdisVersion;

    struct _DRIVER_BLOCK       *NextDriverBlock;

    // pointer to driver object this block is associated with
    PDRIVER_OBJECT              DriverObject;
    // intercepted dispatch function for IRP_MJ_PNP
    PDRIVER_DISPATCH            SavedPnPDispatch;

    // Handlers registered by Remote NDIS microport
    RM_DEVICE_INIT_HANDLER      RmInitializeHandler;
    RM_DEVICE_INIT_CMPLT_NOTIFY_HANDLER RmInitCompleteNotifyHandler;
    RM_DEVICE_HALT_HANDLER      RmHaltHandler;
    RM_SHUTDOWN_HANDLER         RmShutdownHandler;
    RM_UNLOAD_HANDLER           RmUnloadHandler;
    RM_SEND_MESSAGE_HANDLER     RmSendMessageHandler;
    RM_RETURN_MESSAGE_HANDLER   RmReturnMessageHandler;

    // "Global" context for Microport
    PVOID                       MicroportContext;
    
    // list of adapters registered for this Miniport driver.
    struct _RNDISMP_ADAPTER    *AdapterList;

    // number of adapters in use with this driver block
    ULONG                       NumberAdapters;

    // sanity check
    ULONG                       Signature;
} DRIVER_BLOCK, *PDRIVER_BLOCK;



typedef
VOID
(*PRNDISMP_MSG_COMPLETE_HANDLER) (
    IN  struct _RNDISMP_MESSAGE_FRAME *     pMsgFrame,
    IN  NDIS_STATUS                         Status
    );



typedef
BOOLEAN
(*PRNDISMP_MSG_HANDLER_FUNC) (
    IN  struct _RNDISMP_ADAPTER *   pAdapter,
    IN  PRNDIS_MESSAGE              pMessage,
    IN  PMDL                        pMdl,
    IN  ULONG                       TotalLength,
    IN  NDIS_HANDLE                 MicroportMessageContext,
    IN  NDIS_STATUS                 ReceiveStatus,
    IN  BOOLEAN                     bMessageCopied
    );

//
// One of these structures for each NDIS_PACKET that we send.
//
typedef struct _RNDISMP_PACKET_WRAPPER
{
    struct _RNDISMP_MESSAGE_FRAME * pMsgFrame;
    PNDIS_PACKET                    pNdisPacket;
    struct _RNDISMP_VC *            pVc;

    // MDL to describe the RNDIS NdisPacket header:
    PMDL                            pHeaderMdl;

    // Last MDL in the list of MDLs describing this RNDIS packet.
    PMDL                            pTailMdl;

    // Space for the RNDIS Packet header:
    UCHAR                           Packet[sizeof(PVOID)];
} RNDISMP_PACKET_WRAPPER, *PRNDISMP_PACKET_WRAPPER;


//
// Structure used to overlay the MiniportReserved field
// of outgoing (sent) packets. 
//
typedef struct _RNDISMP_SEND_PKT_RESERVED 
{
    // Points to the next packet for multi-packet sends.
    PNDIS_PACKET                    pNext;

    // Points to more detailed information about this packet, too much
    // to fit into one PVOID.
    PRNDISMP_PACKET_WRAPPER         pPktWrapper;
} RNDISMP_SEND_PKT_RESERVED, *PRNDISMP_SEND_PKT_RESERVED;


//
// Structure used to TEMPORARILY overlay the MiniportReserved field
// of sent packets -- this is used to link packets in a list pending
// actual transmission from a timeout routine.
//
typedef struct _RNDISMP_SEND_PKT_RESERVED_TEMP
{
    LIST_ENTRY                      Link;
} RNDISMP_SEND_PKT_RESERVED_TEMP, *PRNDISMP_SEND_PKT_RESERVED_TEMP;


//
// Request context - holds information about a pended request (Set or Query)
//
typedef struct _RNDISMP_REQUEST_CONTEXT
{
    PNDIS_REQUEST                   pNdisRequest;
    struct _RNDISMP_VC *            pVc;
    NDIS_OID                        Oid;
    PVOID                           InformationBuffer;
    UINT                            InformationBufferLength;
    PUINT                           pBytesRead;     // for Set
    PUINT                           pBytesWritten;  // for Query
    PUINT                           pBytesNeeded;
    BOOLEAN                         bInternal;
    NDIS_STATUS                     CompletionStatus;
    ULONG                           RetryCount;
    PNDIS_EVENT                     pEvent;
} RNDISMP_REQUEST_CONTEXT, *PRNDISMP_REQUEST_CONTEXT;

//
// Message Frame - generic structure to hold context about all
// messages sent via the microport.
//
typedef struct _RNDISMP_MESSAGE_FRAME
{
    LIST_ENTRY                      Link;           // used to queue this if
                                                    // a response is expected
                                                    // from the device.
    ULONG                           RefCount;       // Determines when to free
                                                    // this message frame.
    struct _RNDISMP_ADAPTER *       pAdapter;
    struct _RNDISMP_VC *            pVc;
    union
    {
        PNDIS_PACKET                pNdisPacket;    // if DATA message
        PRNDISMP_REQUEST_CONTEXT    pReqContext;    // if Request message
    };
    PMDL                            pMessageMdl;    // what goes to the microport
    UINT32                          NdisMessageType;// copied from the RNDIS message
    UINT32                          RequestId;      // to match requests/responses

    PRNDISMP_MSG_COMPLETE_HANDLER   pCallback;      // called on completion of message send

    ULONG                           TicksOnQueue;
    ULONG                           TimeSent;
#if THROTTLE_MESSAGES
    LIST_ENTRY                      PendLink;       // used to queue this
                                                    // pending send to microport
#endif
    ULONG                           Signature;
} RNDISMP_MESSAGE_FRAME, *PRNDISMP_MESSAGE_FRAME;



//
// linked list entry for transport frames (transmit, receive, request)
//
typedef struct _RNDISMP_LIST_ENTRY 
{
    LIST_ENTRY  Link;
} RNDISMP_LIST_ENTRY, *PRNDISMP_LIST_ENTRY;


//
//  RNDIS VC states.
//
typedef enum
{
    RNDISMP_VC_ALLOCATED = 0,
    RNDISMP_VC_CREATING,
    RNDISMP_VC_CREATING_ACTIVATE_PENDING,
    RNDISMP_VC_CREATING_DELETE_PENDING,
    RNDISMP_VC_CREATE_FAILURE,
    RNDISMP_VC_CREATED,
    RNDISMP_VC_ACTIVATING,
    RNDISMP_VC_ACTIVATED,
    RNDISMP_VC_DEACTIVATING,
    RNDISMP_VC_DEACTIVATED,
    RNDISMP_VC_DELETING,
    RNDISMP_VC_DELETE_FAIL

} RNDISMP_VC_STATE;


//
//  RNDIS Call states.
//
typedef enum
{
    RNDISMP_CALL_IDLE
    // others TBD

} RNDISMP_CALL_STATE;


#define NULL_DEVICE_CONTEXT                 0


//
//  All information about a single VC/call.
//
typedef struct _RNDISMP_VC
{
    //  link to list of VCs on adapter.
    LIST_ENTRY                      VcList;

    //  owning adapter
    struct _RNDISMP_ADAPTER *       pAdapter;

    //  VC handle sent to the device, also our hash lookup key.
    UINT32                          VcId;

    //  base VC state
    RNDISMP_VC_STATE                VcState;

    //  call state, relevant only for devices that are call managers.
    RNDISMP_CALL_STATE              CallState;

    ULONG                           RefCount;

    //  NDIS Wrapper's handle for this Vc
    NDIS_HANDLE                     NdisVcHandle;

    //  remote device's context for this VC
    RNDIS_HANDLE                    DeviceVcContext;

    RNDISMP_SPIN_LOCK               Lock;

    //  sends on this VC that haven't been completed.
    ULONG                           PendingSends;

    //  receive indications that haven't been returned to us.
    ULONG                           PendingReceives;

    //  NDIS requests that haven't been completed.
    ULONG                           PendingRequests;

    //  VC activation (or call setup) parameters.
    PCO_CALL_PARAMETERS             pCallParameters;
} RNDISMP_VC, *PRNDISMP_VC;


//
//  VC hash table.
//
#define RNDISMP_VC_HASH_TABLE_SIZE  41

typedef struct _RNDISMP_VC_HASH_TABLE
{
    ULONG                           NumEntries;
    LIST_ENTRY                      HashEntry[RNDISMP_VC_HASH_TABLE_SIZE];

} RNDISMP_VC_HASH_TABLE, *PRNDISMP_VC_HASH_TABLE;


#define RNDISMP_HASH_VCID(_VcId)    ((_VcId) % RNDISMP_VC_HASH_TABLE_SIZE)


//
// High and low watermarks for messages pending
// at the microport
//
#define RNDISMP_PENDED_SEND_HIWAT       0xffff
#define RNDISMP_PENDED_SEND_LOWAT       0xfff


typedef VOID (*RM_MULTIPLE_SEND_HANDLER) ();

//
// This structure contains all the information about a single
// adapter that this driver is controlling
//
typedef struct _RNDISMP_ADAPTER
{
    // This is the handle given by the wrapper for calling NDIS functions.
    NDIS_HANDLE                 MiniportAdapterHandle;

    // pointer to next adapter in list hanging off driver block
    struct _RNDISMP_ADAPTER    *NextAdapter;

    // pointer to driver block for this adapter
    PDRIVER_BLOCK               DriverBlock;

    // Friendly name:
    ANSI_STRING                 FriendlyNameAnsi;
    UNICODE_STRING              FriendlyNameUnicode;

#if THROTTLE_MESSAGES
    // Counters for messages pending at the microport
    ULONG                       HiWatPendedMessages;
    ULONG                       LoWatPendedMessages;
    ULONG                       CurPendedMessages;

    // Messages not yet sent to microport.
    LIST_ENTRY                  WaitingMessageList;
    BOOLEAN                     SendInProgress;
#endif // THROTTLE_MESSAGES
    // Messages sent to microport, awaiting completion
    LIST_ENTRY                  PendingAtMicroportList;
    BOOLEAN                     SendProcessInProgress;
    LIST_ENTRY                  PendingSendProcessList;
    NDIS_TIMER                  SendProcessTimer;

    // Pool of RNDISMP_MESSAGE_FRAME structures
    NPAGED_LOOKASIDE_LIST       MsgFramePool;
    BOOLEAN                     MsgFramePoolAlloced;

    RNDIS_REQUEST_ID            RequestId;

    // Receive Routine Data Area
    NDIS_HANDLE                 ReceivePacketPool;
    NDIS_HANDLE                 ReceiveBufferPool;
    ULONG                       InitialReceiveFrames;
    ULONG                       MaxReceiveFrames;
    NPAGED_LOOKASIDE_LIST       RcvFramePool;
    BOOLEAN                     RcvFramePoolAlloced;
    BOOLEAN                     IndicatingReceives;
    // Messages to be processed.
    LIST_ENTRY                  PendingRcvMessageList;
    NDIS_TIMER                  IndicateTimer;

    // handlers registered by Remote NDIS microport
    RM_DEVICE_INIT_HANDLER      RmInitializeHandler;
    RM_DEVICE_INIT_CMPLT_NOTIFY_HANDLER RmInitCompleteNotifyHandler;
    RM_DEVICE_HALT_HANDLER      RmHaltHandler;
    RM_SHUTDOWN_HANDLER         RmShutdownHandler;
    RM_SEND_MESSAGE_HANDLER     RmSendMessageHandler;
    RM_RETURN_MESSAGE_HANDLER   RmReturnMessageHandler;

    // handler for DoMultipleSend
    RM_MULTIPLE_SEND_HANDLER    MultipleSendFunc;

    // context for microport adapter
    NDIS_HANDLE                 MicroportAdapterContext;

    // pointer to list of OIDs supported
    PNDIS_OID                   SupportedOIDList;

    // size of OID list
    UINT                        SupportedOIDListSize;

    // pointer to list of flags indicating whether the OID is driver or device supported
    PUINT                       OIDHandlerList;

    // size of OID handler list
    UINT                        OIDHandlerListSize;

    // pointer to list of Driver OIDs
    PNDIS_OID                   DriverOIDList;

    // size of Driver OID list, in OIDs
    UINT                        NumDriverOIDs;

    // total number of OIDs we support
    UINT                        NumOIDSupported;

    // medium type supported by the device.
    NDIS_MEDIUM                 Medium;

    // device flags reported by the device.
    ULONG                       DeviceFlags;

    // max NDIS_PACKETs that can be sent in one RNDIS message
    ULONG                       MaxPacketsPerMessage;
    BOOLEAN                     bMultiPacketSupported;

    // max message size supported for receive by the microport
    ULONG                       MaxReceiveSize;

    // max message size supported by the device
    ULONG                       MaxTransferSize;

    // alignment required by the device
    ULONG                       AlignmentIncr;
    ULONG                       AlignmentMask;

    // list of message frames pending completion by the device
    LIST_ENTRY                  PendingFrameList;

    // synchronization
    NDIS_SPIN_LOCK              Lock;

    // timer to see if we need to send a keep alive message
    NDIS_TIMER                  KeepAliveTimer;

    BOOLEAN                     TimerCancelled;

    // timer tick saved last time a message was received from device
    ULONG                       LastMessageFromDevice;

    // used by check for hang handler to determine if the device is in trouble
    BOOLEAN                     NeedReset;

    // are we waiting for a response to NdisReset?
    BOOLEAN                     ResetPending;

    // used by check for hang handler to determine if the device is in trouble
    BOOLEAN                     KeepAliveMessagePending;

    // are we initializing?
    BOOLEAN                     Initing;

    // are we halting?
    BOOLEAN                     Halting;

    // to wait until we complete sending the Halt message
    NDIS_EVENT                  HaltWaitEvent;

    // request ID of last Keepalive message we have sent
    RNDIS_REQUEST_ID            KeepAliveMessagePendingId;

    PRNDIS_INITIALIZE_COMPLETE  pInitCompleteMessage;

    // are we running on Win9x (WinMe)?
    BOOLEAN                     bRunningOnWin9x;

    // are we running on Win98 Gold?
    BOOLEAN                     bRunningOnWin98Gold;

    // CONDIS - Vc hash table
    PRNDISMP_VC_HASH_TABLE      pVcHashTable;
    ULONG                       LastVcId;

    // Statistics
    RNDISMP_ADAPTER_STATS       Statistics;
    ULONG                       MaxSendCompleteTime;

    // FDO for this device.
    PVOID                       pDeviceObject;

    // PDO for this device.
    PVOID                       pPhysDeviceObject;

    // MAC options
    ULONG                       MacOptions;

    // sanity check
    ULONG                       Signature;

#ifdef BUILD_WIN9X
    MY_CMCONFIGHANDLER          NdisCmConfigHandler;
    MY_DEVNODE                  DevNode;
    ULONG                       WrapContextOffset;
#endif
#if DBG
    ULONG                       MicroportReceivesOutstanding;
    PUCHAR                      pSendLogBuffer;
    ULONG                       LogBufferSize;
    PUCHAR                      pSendLogWrite;
#endif // DBG


} RNDISMP_ADAPTER, *PRNDISMP_ADAPTER;

typedef
VOID
(*RM_MULTIPLE_SEND_HANDLER) (
     IN PRNDISMP_ADAPTER pAdapter,
     IN PRNDISMP_VC      pVc  OPTIONAL,
     IN PPNDIS_PACKET    PacketArray,
     IN UINT             NumberofPackets);

//
// Structure to keep context about a single received RNDIS message.
//
typedef struct _RNDISMP_RECV_MSG_CONTEXT
{
    LIST_ENTRY                      Link;
    NDIS_HANDLE                     MicroportMessageContext;
    PMDL                            pMdl;
    ULONG                           TotalLength;
    PRNDIS_MESSAGE                  pMessage;
    NDIS_STATUS                     ReceiveStatus;
    BOOLEAN                         bMessageCopied;
    RM_CHANNEL_TYPE                 ChannelType;

} RNDISMP_RECV_MSG_CONTEXT, *PRNDISMP_RECV_MSG_CONTEXT;


//
// Structure to keep context about a single received RNDIS_PACKET -message-.
// Note that this can contain more than one packet. We store a pointer to
// this structure in our reserved section of each received NDIS_PACKET.
//
typedef struct _RNDISMP_RECV_DATA_FRAME
{
    NDIS_HANDLE                     MicroportMessageContext;
    union {
        PMDL                        pMicroportMdl;
        PRNDIS_MESSAGE              pLocalMessageCopy;
    };
    ULONG                           ReturnsPending;
    BOOLEAN                         bMessageCopy;       // did we make a copy?
} RNDISMP_RECV_DATA_FRAME, *PRNDISMP_RECV_DATA_FRAME;


//
// Per NDIS_PACKET context for received packets. This goes into MiniportReserved.
//
typedef struct _RNDISMP_RECV_PKT_RESERVED
{
    PRNDISMP_RECV_DATA_FRAME        pRcvFrame;
    PRNDISMP_VC                     pVc;
} RNDISMP_RECV_PKT_RESERVED, *PRNDISMP_RECV_PKT_RESERVED;


//
// Used to overlay ProtocolReserved in a packet queued for indicating up.
//
typedef struct _RNDISMP_RECV_PKT_LINKAGE
{
    LIST_ENTRY                      Link;
} RNDISMP_RECV_PKT_LINKAGE, *PRNDISMP_RECV_PKT_LINKAGE;
    

//
// Global Data
//
extern DRIVER_BLOCK             RndismpMiniportBlockListHead;

extern UINT                     RndismpNumMicroports;

extern NDIS_SPIN_LOCK           RndismpGlobalLock;

extern NDIS_OID                 RndismpSupportedOids[];

extern UINT                     RndismpSupportedOidsNum;

extern NDIS_PHYSICAL_ADDRESS    HighestAcceptableMax;

#if DBG

extern UINT                     RndismpDebugFlags;

#endif


//
// Macros
//

// Given a request message type value, return its completion message type
#define RNDIS_COMPLETION(_Type) ((_Type) | 0x80000000)


// Convert an RNdisMediumXXX value to its NdisMediumXXX equivalent
#define RNDIS_TO_NDIS_MEDIUM(_RndisMedium)  ((NDIS_MEDIUM)(_RndisMedium))

#define RNDISMP_GET_ALIGNED_LENGTH(_AlignedLength, _InputLen, _pAdapter)    \
{                                                                           \
    ULONG       _Length = _InputLen;                                        \
    if (_Length == 0)                                                       \
        (_AlignedLength) = 0;                                               \
    else                                                                    \
        (_AlignedLength) = ((_Length + (_pAdapter)->AlignmentIncr) &        \
                            (_pAdapter)->AlignmentMask);                    \
}

// The minimum MessageLength expected in an RNDIS message of a given type.
#define RNDISMP_MIN_MESSAGE_LENGTH(_MsgTypeField)                           \
    FIELD_OFFSET(RNDIS_MESSAGE, Message) + sizeof(((PRNDIS_MESSAGE)0)->Message._MsgTypeField##)

// memory move macro
#define RNDISMP_MOVE_MEM(dest,src,size) NdisMoveMemory(dest,src,size)

// Macros to extract high and low bytes of a word.
#define MSB(Value) ((UCHAR)((((ULONG)Value) >> 8) & 0xff))
#define LSB(Value) ((UCHAR)(((ULONG)Value) & 0xff))


// Acquire the adapter lock
#define RNDISMP_ACQUIRE_ADAPTER_LOCK(_pAdapter) \
    NdisAcquireSpinLock(&(_pAdapter)->Lock);

// Release the adapter lock
#define RNDISMP_RELEASE_ADAPTER_LOCK(_pAdapter) \
    NdisReleaseSpinLock(&(_pAdapter)->Lock);

// Increment adapter statistics.
#define RNDISMP_INCR_STAT(_pAdapter, _StatsCount)               \
    NdisInterlockedIncrement(&(_pAdapter)->Statistics._StatsCount)

// Get adapter statistics
#define RNDISMP_GET_ADAPTER_STATS(_pAdapter, _StatsCount)           \
    ((_pAdapter)->Statistics._StatsCount)

// Get the send packet reserved field
#define PRNDISMP_RESERVED_FROM_SEND_PACKET(_Packet)             \
    ((PRNDISMP_SEND_PKT_RESERVED)((_Packet)->MiniportReserved))

#define PRNDISMP_RESERVED_TEMP_FROM_SEND_PACKET(_Packet)        \
    ((PRNDISMP_SEND_PKT_RESERVED_TEMP)((_Packet)->MiniportReserved))

#define PRNDISMP_RESERVED_FROM_RECV_PACKET(_Packet)             \
    ((PRNDISMP_RECV_PKT_RESERVED)((_Packet)->MiniportReserved))

// store receive frame context in miniport reserved field
#define RECEIVE_FRAME_TO_NDIS_PACKET(_Packet, _ReceiveFrame)    \
{                                                               \
    PRNDISMP_RECEIVE_FRAME  *TmpPtr;                            \
    TmpPtr  = (PRNDISMP_RECEIVE_FRAME *)                        \
              &(_Packet->MiniportReserved);                     \
    *TmpPtr = _ReceiveFrame;                                    \
}


// Get adapter context from handle passed in NDIS routines
#define PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(_Handle)           \
    ((PRNDISMP_ADAPTER)(_Handle))

// Get miniport context handle from adapter context
#define CONTEXT_HANDLE_FROM_PRNDISMP_ADAPTER(_Ptr)              \
    ((NDIS_HANDLE)(_Ptr))

// Get VC context from handle passed in from NDIS
#define PRNDISMP_VC_FROM_CONTEXT_HANDLE(_Handle)                   \
    ((PRNDISMP_VC)(_Handle))

// Get miniport context from VC
#define CONTEXT_HANDLE_FROM_PRNDISMP_VC(_pVc)                   \
    ((NDIS_HANDLE)(_Vc))

// Get message frame from message handle
#define MESSAGE_FRAME_FROM_HANDLE(_Handle)                      \
    ((PRNDISMP_MESSAGE_FRAME)(_Handle))

// Get a pointer to the data buff in an RNDIS_PACKET
#define GET_PTR_TO_RNDIS_DATA_BUFF(_Message)                    \
    ((PVOID) ((PUCHAR)(_Message) +  _Message->DataOffset))

// Get a pointer to the OOBD data in an RNDIS_PACKET
#define GET_PTR_TO_OOB_DATA(_Message)                           \
    ((PVOID) ((PUCHAR)(_Message) +  _Message->OOBDataOffset))

// Get a pointer to the per packet info in an RNDIS_PACKET
#define GET_PTR_TO_PER_PACKET_INFO(_Message)                    \
    ((PVOID) ((PUCHAR)(_Message) +  _Message->PerPacketInfoOffset))

// Get an offset to the data buff in an RNDIS_PACKET
#define GET_OFFSET_TO_RNDIS_DATA_BUFF(_Message)                 \
    (sizeof(RNDIS_PACKET))

// Get an offset to the OOBD data in an RNDIS_PACKET
#define GET_OFFSET_TO_OOB_DATA(_Message)                        \
    (sizeof(RNDIS_PACKET) +  Message->DataLength)

// Get an offset to the per packet info in an RNDIS_PACKET
#define GET_OFFSET_TO_PER_PACKET_INFO(_Message)                 \
    (sizeof(RNDIS_PACKET) + _Message->DataLength + _Message->OOBDataLength)

#define RNDISMP_GET_INFO_BUFFER_FROM_QUERY_MSG(_Message)        \
    ((PUCHAR)(_Message) + (_Message)->InformationBufferOffset)

#define MIN(x,y) ((x > y) ? y : x)


// Return the virtual address for a received message MDL.
#if NDIS_WDM
#define RNDISMP_GET_MDL_ADDRESS(_pMdl)  MmGetSystemAddressForMdl(_pMdl)
#else
#define RNDISMP_GET_MDL_ADDRESS(_pMdl)  MmGetSystemAddressForMdlSafe(_pMdl, NormalPagePriority)
#endif

// Return the MDL chained to this MDL
#define RNDISMP_GET_MDL_NEXT(_pMdl) ((_pMdl)->Next)

// Return the MDL length
#define RNDISMP_GET_MDL_LENGTH(_pMdl)   MmGetMdlByteCount(_pMdl)

// Access the RNDIS message from our Message Frame structure.
#define RNDISMP_GET_MSG_FROM_FRAME(_pMsgFrame)                  \
    RNDISMP_GET_MDL_ADDRESS(_pMsgFrame->pMessageMdl)

// Return an RNDIS message back to the microport.
#if DBG

#define RNDISMP_RETURN_TO_MICROPORT(_pAdapter, _pMdl, _MicroportMsgContext) \
{                                                                           \
    NdisInterlockedDecrement(&(_pAdapter)->MicroportReceivesOutstanding);   \
    (_pAdapter)->RmReturnMessageHandler((_pAdapter)->MicroportAdapterContext,\
                                        (_pMdl),                            \
                                        (_MicroportMsgContext));            \
}

#else

#define RNDISMP_RETURN_TO_MICROPORT(_pAdapter, _pMdl, _MicroportMsgContext) \
    (_pAdapter)->RmReturnMessageHandler((_pAdapter)->MicroportAdapterContext,\
                                        (_pMdl),                            \
                                        (_MicroportMsgContext))
#endif // DBG

// Send an RNDIS message to the microport.
#if THROTTLE_MESSAGES
#define RNDISMP_SEND_TO_MICROPORT(_pAdapter, _pMsgFrame, _bQueueForResponse, _CallbackFunc)     \
{                                                                           \
    TRACE2(("Send: Adapter %x, MsgFrame %x, Mdl %x\n",                      \
                _pAdapter, _pMsgFrame, _pMsgFrame->pMessageMdl));           \
    (_pMsgFrame)->pCallback = _CallbackFunc;                                \
    QueueMessageToMicroport(_pAdapter, _pMsgFrame, _bQueueForResponse);     \
}
#else
#define RNDISMP_SEND_TO_MICROPORT(_pAdapter, _pMsgFrame, _bQueueForResponse, _CallbackFunc)     \
{                                                                           \
    (_pMsgFrame)->pCallback = _CallbackFunc;                                \
    if (_bQueueForResponse)                                                 \
    {                                                                       \
        RNDISMP_ACQUIRE_ADAPTER_LOCK(_pAdapter);                            \
        InsertTailList(&(_pAdapter)->PendingFrameList, &(_pMsgFrame)->Link);\
        RNDISMP_RELEASE_ADAPTER_LOCK(_pAdapter);                            \
    }                                                                       \
    (_pAdapter)->RmSendMessageHandler((_pAdapter)->MicroportAdapterContext, \
                                              (_pMsgFrame)->pMessageMdl,    \
                                              (_pMsgFrame));                \
}
#endif // THROTTLE_MESSAGES

// Return the handler function for a given message type.
#define RNDISMP_GET_MSG_HANDLER(_pMsgHandlerFunc, _MessageType) \
{                                                               \
    switch (_MessageType)                                       \
    {                                                           \
        case REMOTE_NDIS_HALT_MSG:                              \
            _pMsgHandlerFunc = HaltMessage;                     \
            break;                                              \
        case REMOTE_NDIS_PACKET_MSG:                            \
            _pMsgHandlerFunc = ReceivePacketMessage;            \
            break;                                              \
        case REMOTE_NDIS_INDICATE_STATUS_MSG:                   \
            _pMsgHandlerFunc = IndicateStatusMessage;           \
            break;                                              \
        case REMOTE_NDIS_QUERY_CMPLT:                           \
        case REMOTE_NDIS_SET_CMPLT:                             \
            _pMsgHandlerFunc = QuerySetCompletionMessage;       \
            break;                                              \
        case REMOTE_NDIS_KEEPALIVE_MSG:                         \
            _pMsgHandlerFunc = KeepAliveMessage;                \
            break;                                              \
        case REMOTE_NDIS_KEEPALIVE_CMPLT:                       \
            _pMsgHandlerFunc = KeepAliveCompletionMessage;      \
            break;                                              \
        case REMOTE_NDIS_RESET_CMPLT:                           \
            _pMsgHandlerFunc = ResetCompletionMessage;          \
            break;                                              \
        case REMOTE_NDIS_INITIALIZE_CMPLT:                      \
            _pMsgHandlerFunc = InitCompletionMessage;           \
            break;                                              \
        case REMOTE_CONDIS_MP_CREATE_VC_CMPLT:                  \
            _pMsgHandlerFunc = ReceiveCreateVcComplete;         \
            break;                                              \
        case REMOTE_CONDIS_MP_DELETE_VC_CMPLT:                  \
            _pMsgHandlerFunc = ReceiveDeleteVcComplete;         \
            break;                                              \
        case REMOTE_CONDIS_MP_ACTIVATE_VC_CMPLT:                \
            _pMsgHandlerFunc = ReceiveActivateVcComplete;       \
            break;                                              \
        case REMOTE_CONDIS_MP_DEACTIVATE_VC_CMPLT:              \
            _pMsgHandlerFunc = ReceiveDeactivateVcComplete;     \
            break;                                              \
        default:                                                \
            _pMsgHandlerFunc = UnknownMessage;                  \
            break;                                              \
    }                                                           \
}



//
// Look up a message frame on the adapter given a request ID. If found,
// remove it from the pending list and return it.
//
#define RNDISMP_LOOKUP_PENDING_MESSAGE(_pMsgFrame, _pAdapter, _ReqId)       \
{                                                                           \
    PLIST_ENTRY             _pEnt;                                          \
    PRNDISMP_MESSAGE_FRAME  _pFrame;                                        \
                                                                            \
    (_pMsgFrame) = NULL;                                                    \
    RNDISMP_ACQUIRE_ADAPTER_LOCK(_pAdapter);                                \
    for (_pEnt = (_pAdapter)->PendingFrameList.Flink;                       \
         _pEnt != &(_pAdapter)->PendingFrameList;                           \
         _pEnt = _pEnt->Flink)                                              \
    {                                                                       \
        _pFrame = CONTAINING_RECORD(_pEnt, RNDISMP_MESSAGE_FRAME, Link);    \
        if (_pFrame->RequestId == (_ReqId))                                 \
        {                                                                   \
            RemoveEntryList(_pEnt);                                         \
            (_pMsgFrame) = _pFrame;                                         \
            break;                                                          \
        }                                                                   \
    }                                                                       \
    RNDISMP_RELEASE_ADAPTER_LOCK(_pAdapter);                                \
}


#if DBG_TIME_STAMPS
#define RNDISMP_GET_TIME_STAMP(_pTs)                                        \
{                                                                           \
    LONGLONG systime_usec;                                                  \
    NdisGetCurrentSystemTime((PVOID)&systime_usec);                         \
    *_pTs = (ULONG)((*(PULONG)&systime_usec)/1000);                         \
}
#else
#define RNDISMP_GET_TIME_STAMP(_pTs)
#endif

#define RNDISMP_INIT_LOCK(_pLock)                                           \
    NdisAllocateSpinLock((_pLock));

#define RNDISMP_ACQUIRE_LOCK(_pLock)                                        \
    NdisAcquireSpinLock((_pLock));

#define RNDISMP_RELEASE_LOCK(_pLock)                                        \
    NdisReleaseSpinLock((_pLock));

#define RNDISMP_ACQUIRE_LOCK_DPC(_pLock)                                    \
    NdisDprAcquireSpinLock((_pLock));

#define RNDISMP_RELEASE_LOCK_DPC(_pLock)                                    \
    NdisDprReleaseSpinLock((_pLock));


#define RNDISMP_INIT_VC_LOCK(_pVc)                                          \
    RNDISMP_INIT_LOCK(&((_pVc)->Lock))

#define RNDISMP_ACQUIRE_VC_LOCK(_pVc)                                       \
    RNDISMP_ACQUIRE_LOCK(&((_pVc))->Lock)

#define RNDISMP_RELEASE_VC_LOCK(_pVc)                                       \
    RNDISMP_RELEASE_LOCK(&((_pVc))->Lock)
   
#define RNDISMP_ACQUIRE_VC_LOCK_DPC(_pVc)                                   \
    RNDISMP_ACQUIRE_LOCK_DPC(&((_pVc))->Lock)

#define RNDISMP_RELEASE_VC_LOCK_DPC(_pVc)                                   \
    RNDISMP_RELEASE_LOCK_DPC(&((_pVc))->Lock)


#define RNDISMP_REF_VC(_pVc)                                                \
    NdisInterlockedIncrement(&(_pVc)->RefCount);

#define RNDISMP_DEREF_VC(_pVc, _pRefCount)                                  \
    {                                                                       \
        ULONG       _RefCount;                                              \
                                                                            \
        RNDISMP_ACQUIRE_VC_LOCK(_pVc);                                      \
                                                                            \
        RNDISMP_DEREF_VC_LOCKED(_pVc, &_RefCount);                          \
        *(_pRefCount) = _RefCount;                                          \
        if (_RefCount != 0)                                                 \
        {                                                                   \
            RNDISMP_RELEASE_VC_LOCK(_pVc);                                  \
        }                                                                   \
    }

#define RNDISMP_DEREF_VC_LOCKED(_pVc, _pRefCount)                           \
    {                                                                       \
        ULONG       __RefCount;                                             \
        NDIS_HANDLE __NdisVcHandle;                                         \
                                                                            \
        __RefCount = NdisInterlockedDecrement(&(_pVc)->RefCount);           \
        *(_pRefCount) = __RefCount;                                         \
        if (__RefCount == 0)                                                \
        {                                                                   \
            RNDISMP_RELEASE_VC_LOCK(_pVc);                                  \
            DeallocateVc(_pVc);                                             \
        }                                                                   \
        else                                                                \
        {                                                                   \
            if ((__RefCount == 1) &&                                        \
                ((_pVc)->VcState == RNDISMP_VC_DEACTIVATED))                \
            {                                                               \
                __NdisVcHandle = (_pVc)->NdisVcHandle;                      \
                (_pVc)->VcState = RNDISMP_VC_CREATED;                       \
                NdisInterlockedIncrement(&(_pVc)->RefCount);                \
                                                                            \
                RNDISMP_RELEASE_VC_LOCK(_pVc);                              \
                                                                            \
                NdisMCoDeactivateVcComplete(NDIS_STATUS_SUCCESS,            \
                                            __NdisVcHandle);                \
                                                                            \
                RNDISMP_ACQUIRE_VC_LOCK(_pVc);                              \
                                                                            \
                __RefCount = NdisInterlockedDecrement(&(_pVc)->RefCount);   \
                *(_pRefCount) = __RefCount;                                 \
                if (__RefCount == 0)                                        \
                {                                                           \
                    RNDISMP_RELEASE_VC_LOCK(_pVc);                          \
                    DeallocateVc(_pVc);                                     \
                }                                                           \
            }                                                               \
        }                                                                   \
    }
           
//
// Prototypes for functions in rndismp.c
//

NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);


NDIS_STATUS
RndisMInitializeWrapper(OUT PNDIS_HANDLE                      pNdisWrapperHandle,
                        IN  PVOID                             MicroportContext,
                        IN  PVOID                             DriverObject,
                        IN  PVOID                             RegistryPath,
                        IN  PRNDIS_MICROPORT_CHARACTERISTICS  pCharacteristics);

VOID
RndismpUnload(IN PDRIVER_OBJECT pDriverObject);

NTSTATUS
DllUnload(VOID);

VOID
RndismpHalt(IN NDIS_HANDLE MiniportAdapterContext);

VOID
RndismpInternalHalt(IN NDIS_HANDLE MiniportAdapterContext,
                    IN BOOLEAN bCalledFromHalt);

NDIS_STATUS
RndismpReconfigure(OUT PNDIS_STATUS pStatus,
                   IN NDIS_HANDLE MiniportAdapterContext,
                   IN NDIS_HANDLE ConfigContext);

NDIS_STATUS
RndismpReset(OUT PBOOLEAN    AddressingReset,
             IN  NDIS_HANDLE MiniportAdapterContext);

BOOLEAN
RndismpCheckForHang(IN NDIS_HANDLE MiniportAdapterContext);

NDIS_STATUS
RndismpInitialize(OUT PNDIS_STATUS  OpenErrorStatus,
                  OUT PUINT         SelectedMediumIndex,
                  IN  PNDIS_MEDIUM  MediumArray,
                  IN  UINT          MediumArraySize,
                  IN  NDIS_HANDLE   MiniportAdapterHandle,
                  IN  NDIS_HANDLE   ConfigurationHandle);

VOID
RndisMSendComplete(IN  NDIS_HANDLE    MiniportAdapterContext,
                   IN  NDIS_HANDLE    RndisMessageHandle,
                   IN  NDIS_STATUS    SendStatus);


BOOLEAN
InitCompletionMessage(IN PRNDISMP_ADAPTER   pAdapter,
                      IN PRNDIS_MESSAGE     pMessage,
                      IN PMDL               pMdl,
                      IN ULONG              TotalLength,
                      IN NDIS_HANDLE        MicroportMessageContext,
                      IN NDIS_STATUS        ReceiveStatus,
                      IN BOOLEAN            bMessageCopied);

BOOLEAN
HaltMessage(IN PRNDISMP_ADAPTER   pAdapter,
            IN PRNDIS_MESSAGE     pMessage,
            IN PMDL               pMdl,
            IN ULONG              TotalLength,
            IN NDIS_HANDLE        MicroportMessageContext,
            IN NDIS_STATUS        ReceiveStatus,
            IN BOOLEAN            bMessageCopied);

BOOLEAN
ResetCompletionMessage(IN PRNDISMP_ADAPTER   pAdapter,
                       IN PRNDIS_MESSAGE     pMessage,
                       IN PMDL               pMdl,
                       IN ULONG              TotalLength,
                       IN NDIS_HANDLE        MicroportMessageContext,
                       IN NDIS_STATUS        ReceiveStatus,
                       IN BOOLEAN            bMessageCopied);

BOOLEAN
KeepAliveCompletionMessage(IN PRNDISMP_ADAPTER   pAdapter,
                           IN PRNDIS_MESSAGE     pMessage,
                           IN PMDL               pMdl,
                           IN ULONG              TotalLength,
                           IN NDIS_HANDLE        MicroportMessageContext,
                           IN NDIS_STATUS        ReceiveStatus,
                           IN BOOLEAN            bMessageCopied);


BOOLEAN
KeepAliveMessage(IN PRNDISMP_ADAPTER   pAdapter,
                 IN PRNDIS_MESSAGE     pMessage,
                 IN PMDL               pMdl,
                 IN ULONG              TotalLength,
                 IN NDIS_HANDLE        MicroportMessageContext,
                 IN NDIS_STATUS        ReceiveStatus,
                 IN BOOLEAN            bMessageCopied);

VOID
RndismpShutdownHandler(IN NDIS_HANDLE MiniportAdapterContext);

VOID
RndismpDisableInterrupt(IN NDIS_HANDLE MiniportAdapterContext);

VOID
RndismpEnableInterrupt(IN NDIS_HANDLE MiniportAdapterContext);

VOID
RndismpHandleInterrupt(IN NDIS_HANDLE MiniportAdapterContext);

VOID
RndismpIsr(OUT PBOOLEAN InterruptRecognized,
           OUT PBOOLEAN QueueDpc,
           IN  PVOID    Context);

VOID
CompleteSendHalt(IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
                 IN NDIS_STATUS SendStatus);

VOID
CompleteSendReset(IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
                  IN NDIS_STATUS SendStatus);

VOID
CompleteMiniportReset(IN PRNDISMP_ADAPTER pAdapter,
                      IN NDIS_STATUS ResetStatus,
                      IN BOOLEAN AddressingReset);

NDIS_STATUS
ReadAndSetRegistryParameters(IN PRNDISMP_ADAPTER pAdapter,
                             IN NDIS_HANDLE ConfigurationContext);

NDIS_STATUS
SendConfiguredParameter(IN PRNDISMP_ADAPTER     pAdapter,
                        IN NDIS_HANDLE          ConfigHandle,
                        IN PNDIS_STRING         pParameterName,
                        IN PNDIS_STRING         pParameterType);

VOID
RndismpPnPEventNotify(IN NDIS_HANDLE MiniportAdapterContext,
                      IN NDIS_DEVICE_PNP_EVENT EventCode,
                      IN PVOID InformationBuffer,
                      IN ULONG InformationBufferLength);

//
// Prototypes for functions in init.c
//

NDIS_STATUS
SetupSendQueues(IN PRNDISMP_ADAPTER Adapter);

NDIS_STATUS
SetupReceiveQueues(IN PRNDISMP_ADAPTER Adapter);

NDIS_STATUS
AllocateTransportResources(IN PRNDISMP_ADAPTER Adapter);

VOID
FreeTransportResources(IN PRNDISMP_ADAPTER Adapter);

VOID
FreeSendResources(IN PRNDISMP_ADAPTER Adapter);

VOID
FreeReceiveResources(IN PRNDISMP_ADAPTER Adapter);


//
// Prototypes for functions in receive.c
//

VOID
RndismpReturnPacket(IN NDIS_HANDLE    MiniportAdapterContext,
                    IN PNDIS_PACKET   Packet);

VOID
DereferenceRcvFrame(IN PRNDISMP_RECV_DATA_FRAME pRcvFrame,
                    IN PRNDISMP_ADAPTER         pAdapter);

VOID
RndisMIndicateReceive(IN NDIS_HANDLE        MiniportAdapterContext,
                      IN PMDL               pMessageHead,
                      IN NDIS_HANDLE        MicroportMessageContext,
                      IN RM_CHANNEL_TYPE    ChannelType,
                      IN NDIS_STATUS        ReceiveStatus);
VOID
IndicateReceive(IN PRNDISMP_ADAPTER         pAdapter,
                IN PRNDISMP_VC              pVc OPTIONAL,
                IN PRNDISMP_RECV_DATA_FRAME pRcvFrame,
                IN PPNDIS_PACKET            PacketArray,
                IN ULONG                    NumberOfPackets,
                IN NDIS_STATUS              ReceiveStatus);

PRNDIS_MESSAGE
CoalesceMultiMdlMessage(IN PMDL         pMdl,
                        IN ULONG        TotalLength);

VOID
FreeRcvMessageCopy(IN PRNDIS_MESSAGE    pMessage);

BOOLEAN
ReceivePacketMessage(IN PRNDISMP_ADAPTER    pAdapter,
                     IN PRNDIS_MESSAGE      pMessage,
                     IN PMDL                pMdl,
                     IN ULONG               TotalLength,
                     IN NDIS_HANDLE         MicroportMessageContext,
                     IN NDIS_STATUS         ReceiveStatus,
                     IN BOOLEAN             bMessageCopied);

BOOLEAN
ReceivePacketMessageRaw(IN PRNDISMP_ADAPTER    pAdapter,
                        IN PRNDIS_MESSAGE      pMessage,
                        IN PMDL                pMdl,
                        IN ULONG               TotalLength,
                        IN NDIS_HANDLE         MicroportMessageContext,
                        IN NDIS_STATUS         ReceiveStatus,
                        IN BOOLEAN             bMessageCopied);

BOOLEAN
IndicateStatusMessage(IN PRNDISMP_ADAPTER   pAdapter,
                      IN PRNDIS_MESSAGE     pMessage,
                      IN PMDL               pMdl,
                      IN ULONG              TotalLength,
                      IN NDIS_HANDLE        MicroportMessageContext,
                      IN NDIS_STATUS        ReceiveStatus,
                      IN BOOLEAN            bMessageCopied);

BOOLEAN
UnknownMessage(IN PRNDISMP_ADAPTER   pAdapter,
               IN PRNDIS_MESSAGE     pMessage,
               IN PMDL               pMdl,
               IN ULONG              TotalLength,
               IN NDIS_HANDLE        MicroportMessageContext,
               IN NDIS_STATUS        ReceiveStatus,
               IN BOOLEAN            bMessageCopied);

PRNDISMP_RECV_DATA_FRAME
AllocateReceiveFrame(IN PRNDISMP_ADAPTER    pAdapter);

VOID
FreeReceiveFrame(IN PRNDISMP_RECV_DATA_FRAME    pRcvFrame,
                 IN PRNDISMP_ADAPTER            pAdapter);

VOID
IndicateTimeout(IN PVOID SystemSpecific1,
                IN PVOID Context,
                IN PVOID SystemSpecific2,
                IN PVOID SystemSpecific3);

//
// Prototypes for functions in send.c
//

VOID
RndismpMultipleSend(IN NDIS_HANDLE   MiniportAdapterContext,
                    IN PPNDIS_PACKET PacketArray,
                    IN UINT          NumberOfPackets);

VOID
DoMultipleSend(IN PRNDISMP_ADAPTER  pAdapter,
               IN PRNDISMP_VC       pVc OPTIONAL,
               IN PPNDIS_PACKET     PacketArray,
               IN UINT              NumberOfPackets);

VOID
DoMultipleSendRaw(IN PRNDISMP_ADAPTER  pAdapter,
                  IN PRNDISMP_VC       pVc OPTIONAL,
                  IN PPNDIS_PACKET     PacketArray,
                  IN UINT              NumberOfPackets);

PRNDISMP_PACKET_WRAPPER
PrepareDataMessage(IN   PNDIS_PACKET            pNdisPacket,
                   IN   PRNDISMP_ADAPTER        pAdapter,
                   IN   PRNDISMP_VC             pVc         OPTIONAL,
                   IN OUT PULONG                pTotalMessageLength);

PRNDISMP_PACKET_WRAPPER
PrepareDataMessageRaw(IN   PNDIS_PACKET            pNdisPacket,
                      IN   PRNDISMP_ADAPTER        pAdapter,
                      IN OUT PULONG                pTotalMessageLength);

PRNDISMP_PACKET_WRAPPER
AllocatePacketMsgWrapper(IN PRNDISMP_ADAPTER        pAdapter,
                         IN ULONG                   MsgHeaderLength);

VOID
FreePacketMsgWrapper(IN PRNDISMP_PACKET_WRAPPER     pPktWrapper);

VOID
CompleteSendData(IN  PRNDISMP_MESSAGE_FRAME pMsgFrame,
                 IN  NDIS_STATUS            SendStatus);

VOID
FreeMsgAfterSend(IN  PRNDISMP_MESSAGE_FRAME pMsgFrame,
                 IN  NDIS_STATUS            SendStatus);

#if THROTTLE_MESSAGES
VOID
QueueMessageToMicroport(IN PRNDISMP_ADAPTER pAdapter,
                        IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
                        IN BOOLEAN          bQueueMessageForResponse);
VOID
FlushPendingMessages(IN  PRNDISMP_ADAPTER        pAdapter);
#endif

VOID
SendProcessTimeout(IN PVOID SystemSpecific1,
                  IN PVOID Context,
                  IN PVOID SystemSpecific2,
                  IN PVOID SystemSpecific3);

//
// Prototypes for functions in request.c
//

NDIS_STATUS
RndismpQueryInformation(IN  NDIS_HANDLE MiniportAdapterContext,
                        IN  NDIS_OID    Oid,
                        IN  PVOID       InformationBuffer,
                        IN  ULONG       InformationBufferLength,
                        OUT PULONG      pBytesWritten,
                        OUT PULONG      pBytesNeeded);
NDIS_STATUS
ProcessQueryInformation(IN  PRNDISMP_ADAPTER    pAdapter,
                        IN  PRNDISMP_VC         pVc,
                        IN  PNDIS_REQUEST       pRequest,
                        IN  NDIS_OID            Oid,
                        IN  PVOID               InformationBuffer,
                        IN  ULONG               InformationBufferLength,
                        OUT PULONG              pBytesWritten,
                        OUT PULONG              pBytesNeeded);

NDIS_STATUS
RndismpSetInformation(IN  NDIS_HANDLE   MiniportAdapterContext,
                      IN  NDIS_OID      Oid,
                      IN  PVOID         InformationBuffer,
                      IN  ULONG         InformationBufferLength,
                      OUT PULONG        pBytesRead,
                      OUT PULONG        pBytesNeeded);

NDIS_STATUS
ProcessSetInformation(IN  PRNDISMP_ADAPTER    pAdapter,
                      IN  PRNDISMP_VC         pVc OPTIONAL,
                      IN  PNDIS_REQUEST       pRequest OPTIONAL,
                      IN  NDIS_OID            Oid,
                      IN  PVOID               InformationBuffer,
                      IN  ULONG               InformationBufferLength,
                      OUT PULONG              pBytesRead,
                      OUT PULONG              pBytesNeeded);

NDIS_STATUS
DriverQueryInformation(IN  PRNDISMP_ADAPTER pAdapter,
                       IN  PRNDISMP_VC      pVc OPTIONAL,
                       IN  PNDIS_REQUEST    pRequest OPTIONAL,
                       IN  NDIS_OID         Oid,
                       IN  PVOID            InformationBuffer,
                       IN  ULONG            InformationBufferLength,
                       OUT PULONG           pBytesWritten,
                       OUT PULONG           pBytesNeeded);

NDIS_STATUS
DeviceQueryInformation(IN  PRNDISMP_ADAPTER pAdapter,
                       IN  PRNDISMP_VC      pVc OPTIONAL,
                       IN  PNDIS_REQUEST    pRequest OPTIONAL,
                       IN  NDIS_OID         Oid,
                       IN  PVOID            InformationBuffer,
                       IN  ULONG            InformationBufferLength,
                       OUT PULONG           pBytesWritten,
                       OUT PULONG           pBytesNeeded);

NDIS_STATUS
DriverSetInformation(IN  PRNDISMP_ADAPTER   pAdapter,
                     IN  PRNDISMP_VC        pVc OPTIONAL,
                     IN  PNDIS_REQUEST      pRequest OPTIONAL,
                     IN  NDIS_OID           Oid,
                     IN  PVOID              InformationBuffer,
                     IN  ULONG              InformationBufferLength,
                     OUT PULONG             pBytesRead,
                     OUT PULONG             pBytesNeeded);

NDIS_STATUS
DeviceSetInformation(IN  PRNDISMP_ADAPTER   pAdapter,
                     IN  PRNDISMP_VC        pVc OPTIONAL,
                     IN  PNDIS_REQUEST      pRequest OPTIONAL,
                     IN  NDIS_OID           Oid,
                     IN  PVOID              InformationBuffer,
                     IN  ULONG              InformationBufferLength,
                     OUT PULONG             pBytesRead,
                     OUT PULONG             pBytesNeeded);

BOOLEAN
QuerySetCompletionMessage(IN PRNDISMP_ADAPTER   pAdapter,
                          IN PRNDIS_MESSAGE     pMessage,
                          IN PMDL               pMdl,
                          IN ULONG              TotalLength,
                          IN NDIS_HANDLE        MicroportMessageContext,
                          IN NDIS_STATUS        ReceiveStatus,
                          IN BOOLEAN            bMessageCopied);

VOID
CompleteSendDeviceRequest(IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
                          IN NDIS_STATUS            SendStatus);

#ifdef BUILD_WIN9X

VOID
CompleteSendDiscardDeviceRequest(IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
                                 IN NDIS_STATUS            SendStatus);

#endif // BUILD_WIN9X


NDIS_STATUS
BuildOIDLists(IN PRNDISMP_ADAPTER  Adapter, 
              IN PNDIS_OID         DeviceOIDList,
              IN UINT              NumDeviceOID,
              IN PNDIS_OID         DriverOIDList,
              IN UINT              NumDriverOID);

UINT
GetOIDSupport(IN PRNDISMP_ADAPTER Adapter, IN NDIS_OID Oid);

VOID
FreeOIDLists(IN PRNDISMP_ADAPTER Adapter);

PRNDISMP_REQUEST_CONTEXT
AllocateRequestContext(IN PRNDISMP_ADAPTER pAdapter);

VOID
FreeRequestContext(IN PRNDISMP_ADAPTER pAdapter,
                   IN PRNDISMP_REQUEST_CONTEXT pReqContext);


//
// Prototypes for functions in util.c
//

NDIS_STATUS
MemAlloc(OUT PVOID *Buffer, IN UINT Length);

VOID
MemFree(IN PVOID Buffer, IN UINT Length);

VOID
AddAdapter(IN PRNDISMP_ADAPTER Adapter);

VOID
RemoveAdapter(IN PRNDISMP_ADAPTER Adapter);

VOID
DeviceObjectToAdapterAndDriverBlock(IN PDEVICE_OBJECT pDeviceObject,
                                    OUT PRNDISMP_ADAPTER * ppAdapter,
                                    OUT PDRIVER_BLOCK * ppDriverBlock);

VOID
AddDriverBlock(IN PDRIVER_BLOCK Head, IN PDRIVER_BLOCK Item);

VOID
RemoveDriverBlock(IN PDRIVER_BLOCK BlockHead, IN PDRIVER_BLOCK Item);

PDRIVER_BLOCK
DeviceObjectToDriverBlock(IN PDRIVER_BLOCK Head, 
                          IN PDEVICE_OBJECT DeviceObject);

PDRIVER_BLOCK
DriverObjectToDriverBlock(IN PDRIVER_BLOCK Head,
                          IN PDRIVER_OBJECT DriverObject);

PRNDISMP_MESSAGE_FRAME
AllocateMsgFrame(IN PRNDISMP_ADAPTER pAdapter);

VOID
DereferenceMsgFrame(IN PRNDISMP_MESSAGE_FRAME pMsgFrame);

VOID
ReferenceMsgFrame(IN PRNDISMP_MESSAGE_FRAME pMsgFrame);

VOID
EnqueueNDISPacket(IN PRNDISMP_ADAPTER Adapter, IN PNDIS_PACKET Packet);

PNDIS_PACKET
DequeueNDISPacket(IN PRNDISMP_ADAPTER Adapter);

VOID
KeepAliveTimerHandler(IN PVOID SystemSpecific1,
                      IN PVOID Context,
                      IN PVOID SystemSpecific2,
                      IN PVOID SystemSpecific3);

VOID
CompleteSendKeepAlive(IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
                      IN NDIS_STATUS SendStatus);

PRNDISMP_MESSAGE_FRAME
BuildRndisMessageCommon(IN  PRNDISMP_ADAPTER  Adapter, 
                        IN  PRNDISMP_VC       pVc,
                        IN  UINT              NdisMessageType,
                        IN  NDIS_OID          Oid,
                        IN  PVOID             InformationBuffer,
                        IN  ULONG             InformationBufferLength);


PRNDISMP_MESSAGE_FRAME
AllocateMessageAndFrame(IN PRNDISMP_ADAPTER Adapter,
                        IN UINT MessageSize);

VOID
FreeAdapter(IN PRNDISMP_ADAPTER pAdapter);

PRNDISMP_VC
AllocateVc(IN PRNDISMP_ADAPTER      pAdapter);

VOID
DeallocateVc(IN PRNDISMP_VC         pVc);

PRNDISMP_VC
LookupVcId(IN PRNDISMP_ADAPTER  pAdapter,
           IN UINT32            VcId);

VOID
EnterVcIntoHashTable(IN PRNDISMP_ADAPTER    pAdapter,
                     IN PRNDISMP_VC         pVc);

VOID
RemoveVcFromHashTable(IN PRNDISMP_ADAPTER   pAdapter,
                      IN PRNDISMP_VC        pVc);

//
// Prototypes for functions in comini.c
//
NDIS_STATUS
RndismpCoCreateVc(IN NDIS_HANDLE    MiniportAdapterContext,
                  IN NDIS_HANDLE    NdisVcHandle,
                  IN PNDIS_HANDLE   pMiniportVcContext);

VOID
CompleteSendCoCreateVc(IN PRNDISMP_MESSAGE_FRAME    pMsgFrame,
                       IN NDIS_STATUS               SendStatus);

VOID
HandleCoCreateVcFailure(IN PRNDISMP_VC      pVc,
                        IN NDIS_STATUS      Status);

NDIS_STATUS
RndismpCoDeleteVc(IN NDIS_HANDLE    MiniportVcContext);

NDIS_STATUS
StartVcDeletion(IN PRNDISMP_VC      pVc);

VOID
CompleteSendCoDeleteVc(IN PRNDISMP_MESSAGE_FRAME    pMsgFrame,
                       IN NDIS_STATUS               SendStatus);

VOID
HandleCoDeleteVcFailure(IN PRNDISMP_VC      pVc,
                        IN NDIS_STATUS      Status);

NDIS_STATUS
RndismpCoActivateVc(IN NDIS_HANDLE          MiniportVcContext,
                    IN PCO_CALL_PARAMETERS  pCallParameters);

NDIS_STATUS
StartVcActivation(IN PRNDISMP_VC            pVc);

VOID
CompleteSendCoActivateVc(IN PRNDISMP_MESSAGE_FRAME      pMsgFrame,
                         IN NDIS_STATUS                 SendStatus);

NDIS_STATUS
RndismpCoDeactivateVc(IN NDIS_HANDLE          MiniportVcContext);

VOID
CompleteSendCoDeactivateVc(IN PRNDISMP_MESSAGE_FRAME    pMsgFrame,
                           IN NDIS_STATUS               SendStatus);

NDIS_STATUS
RndismpCoRequest(IN NDIS_HANDLE          MiniportAdapterContext,
                 IN NDIS_HANDLE          MiniportVcContext,
                 IN OUT PNDIS_REQUEST    pRequest);

VOID
RndismpCoSendPackets(IN NDIS_HANDLE          MiniportVcContext,
                     IN PNDIS_PACKET *       PacketArray,
                     IN UINT                 NumberOfPackets);

BOOLEAN
ReceiveCreateVcComplete(IN PRNDISMP_ADAPTER    pAdapter,
                        IN PRNDIS_MESSAGE      pMessage,
                        IN PMDL                pMdl,
                        IN ULONG               TotalLength,
                        IN NDIS_HANDLE         MicroportMessageContext,
                        IN NDIS_STATUS         ReceiveStatus,
                        IN BOOLEAN             bMessageCopied);

BOOLEAN
ReceiveActivateVcComplete(IN PRNDISMP_ADAPTER    pAdapter,
                          IN PRNDIS_MESSAGE      pMessage,
                          IN PMDL                pMdl,
                          IN ULONG               TotalLength,
                          IN NDIS_HANDLE         MicroportMessageContext,
                          IN NDIS_STATUS         ReceiveStatus,
                          IN BOOLEAN             bMessageCopied);

BOOLEAN
ReceiveDeleteVcComplete(IN PRNDISMP_ADAPTER    pAdapter,
                        IN PRNDIS_MESSAGE      pMessage,
                        IN PMDL                pMdl,
                        IN ULONG               TotalLength,
                        IN NDIS_HANDLE         MicroportMessageContext,
                        IN NDIS_STATUS         ReceiveStatus,
                        IN BOOLEAN             bMessageCopied);

BOOLEAN
ReceiveDeactivateVcComplete(IN PRNDISMP_ADAPTER    pAdapter,
                            IN PRNDIS_MESSAGE      pMessage,
                            IN PMDL                pMdl,
                            IN ULONG               TotalLength,
                            IN NDIS_HANDLE         MicroportMessageContext,
                            IN NDIS_STATUS         ReceiveStatus,
                            IN BOOLEAN             bMessageCopied);

PRNDISMP_MESSAGE_FRAME
BuildRndisMessageCoMiniport(IN  PRNDISMP_ADAPTER    pAdapter,
                            IN  PRNDISMP_VC         pVc,
                            IN  UINT                NdisMessageType,
                            IN  PCO_CALL_PARAMETERS pCallParameters OPTIONAL);

VOID
CompleteSendDataOnVc(IN PRNDISMP_VC         pVc,
                     IN PNDIS_PACKET        pNdisPacket,
                     IN NDIS_STATUS         Status);

VOID
IndicateReceiveDataOnVc(IN PRNDISMP_VC         pVc,
                        IN PNDIS_PACKET *      PacketArray,
                        IN UINT                NumberOfPackets);

//
// Prototypes for functions in wdmutil.c
//

PDRIVER_OBJECT
DeviceObjectToDriverObject(IN PDEVICE_OBJECT DeviceObject);

NTSTATUS
GetDeviceFriendlyName(IN PDEVICE_OBJECT pDeviceObject,
                      OUT PANSI_STRING pAnsiString,
                      OUT PUNICODE_STRING pUnicodeString);

VOID
HookPnpDispatchRoutine(IN PDRIVER_BLOCK    DriverBlock);

NTSTATUS
PnPDispatch(IN PDEVICE_OBJECT       pDeviceObject,
            IN PIRP                 pIrp);

#ifdef BUILD_WIN9X

VOID
HookNtKernCMHandler(IN PRNDISMP_ADAPTER     pAdapter);

VOID
UnHookNtKernCMHandler(IN PRNDISMP_ADAPTER     pAdapter);
MY_CONFIGRET __cdecl
RndisCMHandler(IN MY_CONFIGFUNC         cfFuncName,
               IN MY_SUBCONFIGFUNC      cfSubFuncName,
               IN MY_DEVNODE            cfDevNode,
               IN ULONG                 dwRefData,
               IN ULONG                 ulFlags);

#endif

#if DBG

//
// Prototypes for functions in debug.c
//

PCHAR
GetOidName(IN NDIS_OID Oid);

VOID
DisplayOidList(IN PRNDISMP_ADAPTER Adapter);

VOID
RndisPrintHexDump(PVOID            Pointer,
                  ULONG            Length);

VOID
RndisLogSendMessage(
    IN  PRNDISMP_ADAPTER        pAdapter,
    IN  PRNDISMP_MESSAGE_FRAME  pMsgFrame);

#endif


#endif // _RNDISMP_H_