Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

927 lines
32 KiB

#ifndef _MINIPORT_H_
#define _MINIPORT_H_
#define MP_NDIS_MajorVersion 4
#define MP_NDIS_MinorVersion 0
typedef struct _LINE* PLINE;
typedef struct _CALL* PCALL;
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
These macros will be called by MpWanSend() and PrSendComplete()
functions when a PPPOE_PACKET with references to a packet owned by NDIS is
created and freed, respectively.
---------------------------------------------------------------------------*/
#define MpPacketOwnedByNdiswanReceived( pM ) \
NdisInterlockedIncrement( &(pM)->NumPacketsOwnedByNdiswan )
#define MpPacketOwnedByNdiswanReturned( pM ) \
NdisInterlockedDecrement( &(pM)->NumPacketsOwnedByNdiswan )
typedef struct
_ADAPTER
{
//
// Tag for the adapter control block (used for debugging).
//
ULONG tagAdapter;
//
// Keeps the number of references on this adapter.
// References are added and deleted for the following operations:
//
// (a) A reference is added when the adapter is initialized and removed when
// it is halted.
//
// (b) A reference is added when tapi provider is open, and removed when it is shutdown.
//
LONG lRef;
//
// Spin lock to synchronize access to shared members.
//
NDIS_SPIN_LOCK lockAdapter;
//
// This event will be triggered if MPBF_MiniportHaltPending is set and ref count drops to 0.
//
NDIS_EVENT eventAdapterHalted;
//
// These are the various bit flags to indicate other state information for the adapter:
//
// (a) MPBF_MiniportIdle: Indicates that the miniport is in idle state.
//
// (b) MPBF_MiniportInitialized: Indicates that the miniport is initialized.
// The following pending flags can be set additionally.
// MPBF_MiniportHaltPending
//
// (c) MPBF_MiniportHaltPending: Indicates that a miniport halt operation is pending
// on the adappter.
//
// (d) MPBF_MiniportHalted: Indicates that miniport has halted completely.
// No other flags can be set at this time.
//
ULONG ulMpFlags;
#define MPBF_MiniportIdle 0x00000000
#define MPBF_MiniportInitialized 0x00000001
#define MPBF_MiniportHaltPending 0x00000002
#define MPBF_MiniportHalted 0x00000004
//
// Handle passed to us in MiniportInitialize().
// We should keep it around and pass it back to NDISWAN
// in some functions.
//
NDIS_HANDLE MiniportAdapterHandle;
//
// Number of packets owned by NDISWAN, passed to us and will be returned
// to Ndiswan
//
LONG NumPacketsOwnedByNdiswan;
//
// This is the built-in Tapi Provider context.
// It keeps the tables for lines and calls.
//
struct
{
//
// Keeps references on the tapi provider
// References are added and deleted for the following operations:
//
// (a) A reference is added when TapiProvider is initialized and removed when
// it is shutdown.
//
// (b) A reference is added when a line open, and removed when line is closed.
//
LONG lRef;
//
// Tapi Provider context flags.
//
// (a) TPBF_TapiProvIdle: Indicates that the line is in idle state.
//
// (b) TPBF_TapiProvInitialized: Indicates that TAPI provider is initialized.
//
// (c) TPBF_TapiProvShutdownPending: Indicates that a TAPI provider shutdown operation
// is pending.
//
// (d) TPBF_TapiProvShutdown: Indicates that TAPI provider is shutdown.
//
// (e) LNBF_NotifyNDIS: This flag indicates that an asynchronous completion of a Tapi Provider
// shutdown request must be communicated to NDIS using NdisMSetInformationComplete().
//
ULONG ulTpFlags;
#define TPBF_TapiProvIdle 0x00000000
#define TPBF_TapiProvInitialized 0x00000001
#define TPBF_TapiProvShutdownPending 0x00000002
#define TPBF_TapiProvShutdown 0x00000004
#define TPBF_NotifyNDIS 0x00000008
//
// This is supplied by Tapi.
// It is the base index for enumeration of line devices on this tapi provider.
//
ULONG ulDeviceIDBase;
//
// This is the table that holds pointers to active line contexts.
// (pLine->hdLine is holds the index to this table)
//
PLINE* LineTable;
//
// Current active number of lines
//
UINT nActiveLines;
//
// This table holds the handles to calls.
// It's size is pAdapter->nMaxLines * pAdapter->nCallsPerLine.
//
HANDLE_TABLE hCallTable;
} TapiProv;
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++
typedef struct _NDIS_WAN_INFO {
ULONG MaxFrameSize;
ULONG MaxTransmit;
ULONG HeaderPadding;
ULONG TailPadding;
ULONG Endpoints;
UINT MemoryFlags;
NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress;
ULONG FramingBits;
ULONG DesiredACCM;
} NDIS_WAN_INFO, *PNDIS_WAN_INFO;
-------------------------------------------------------*/
NDIS_WAN_INFO NdisWanInfo;
/////////////////////////////////////////////////////////
//
// Config values read from registry
//
/////////////////////////////////////////////////////////
//
// Indicates the role of the machine:
// - fClientRole is TRUE: Machine acts as a client.
// Only outgoing calls are connected, and no calls are received.
//
// - fClientRole is FALSE: Machine acts as a server.
// Only incoming calls are accepted, and no outgoing calls are allowed.
//
BOOLEAN fClientRole;
//
// This is the string that holds the Service-name this server offers.
// It must be an UTF-8 string per PPPoE RFC.
//
// It is only used for incoming calls.
//
#define MAX_COMPUTERNAME_LENGTH 200
#define SERVICE_NAME_EXTENSION " PPPoE"
#define MAX_SERVICE_NAME_LENGTH 256
CHAR ServiceName[MAX_SERVICE_NAME_LENGTH];
//
// Indicates the length of the Service name string
//
USHORT nServiceNameLength;
//
// This is the string that holds the AC-name for this server.
// It must be an UTF-8 string per PPPoE RFC.
//
// It is only used for incoming calls.
//
#define MAX_AC_NAME_LENGTH 256
CHAR ACName[MAX_AC_NAME_LENGTH];
//
// Indicates the length of the AC name string
//
USHORT nACNameLength;
//
// Max number of simultaneous calls that can be established between the same
// client and server
//
UINT nClientQuota;
//
// Indicates the number of line contexts that will be created.
//
UINT nMaxLines;
//
// Indicates the number of calls that each individual line will support.
//
UINT nCallsPerLine;
//
// Indicates the maximum number of timeouts for the PPPoE FSM.
// When the current number of timeouts , reach this number call will be dropped.
//
UINT nMaxTimeouts;
//
// This is the timeout period for client side operations (in ms)
//
ULONG ulSendTimeout;
//
// This is the timeout period for server side operations (in ms)
//
ULONG ulRecvTimeout;
//
// This shows the maximum number of packets that NDISWAN can pass to us simultaneously.
// This does not make any sense for us as we do not queue the packets, but send them to
// peer directly when we receive them from NDISWAN.
//
UINT nMaxSendPackets;
//
// This is related to the problem where the server does not support the empty service-name.
// In this case, there is no way for clients to discover the services supported by the server,
// since the server sends back a PADO packet without the empty service-name attribute, and we drop
// it (per RFC). So if this value is TRUE, then we break the RFC and do the following:
// If client asks for the empty service name, then we do not ignore the PADO that does not contain
// the empty service-name. Instead we try to find the empty service-name field, and request it if its
// available. If not, then we request the first service available in the PADO.
//
BOOLEAN fAcceptAnyService;
}
ADAPTER;
//
// This is our call line context.
// All information pertinent to a line is kept in this context.
//
typedef struct
_LINE
{
//
// Tag for the line control block (used for debugging).
//
ULONG tagLine;
//
// Keeps reference count on the line control block.
// References are added and deleted for the following operations:
//
// (a) A reference is added when a line is opened and removed when
// line is closed.
//
// (b) A reference is added when a call context is created on the line,
// and removed when call context is cleaned up.
//
LONG lRef;
//
// Spin lock to synchronize access to shared members
//
NDIS_SPIN_LOCK lockLine;
//
// These are the various bit flags to indicate other state information for the line:
//
// (a) LNBF_LineIdle: Indicates that the line is in idle state.
//
// (b) LNBF_LineOpen: Indicates that the line is in open state. Whan this flag is set,
// only the following pending flags may be set additionally:
// LNBF_LineClosePending
//
// (c) LNBF_LineClosePending: This pending flag can be only set only if LNBF_LineOpen is set,
// and indicates that there is a pending line close operation.
//
// (d) LNBF_LineClosed: Indicates that the line is in closed state. When this flag is set,
// no other pending flags can be set.
//
// (e) LNBF_NotifyNDIS: This flag indicates that an asynchronous completion of a close line request
// must be communicated to NDIS using NdisMSetInformationComplete().
//
// (f) LNBF_MakeOutgoingCalls: This flag is set if line is allowed to make outgoing calls.
// It will be set in TpMakeCall() if machine is acting as a client
// (pAdapter->fClientRole is TRUE).
//
// (g) LNBF_AcceptIncomingCalls: This flag is set if TAPI is able to take calls over this line.
// It will be set in TpSetDefaultMediaDetection() if machine is acting as
// a server (pAdapter->fClientRole is FALSE).
//
ULONG ulLnFlags;
#define LNBF_LineIdle 0x00000000
#define LNBF_LineOpen 0x00000001
#define LNBF_LineClosed 0x00000002
#define LNBF_LineClosePending 0x00000004
#define LNBF_NotifyNDIS 0x00000008
#define LNBF_MakeOutgoingCalls 0x00000010
#define LNBF_AcceptIncomingCalls 0x00000020
//
// Back pointer to owning adapter context
//
ADAPTER* pAdapter;
//
// Indicates the maximum number of calls that is permitted on this line.
// Copy of pAdapter->nCallsPerLine.
//
UINT nMaxCalls;
//
// Indicates the number of current call contexts attached to the line.
//
// It will be incremented when a call context is created and attached to a line,
// and decremented when such a call context is destroyed.
//
UINT nActiveCalls;
//
// Link list of calls
//
LIST_ENTRY linkCalls;
//
// This is the handle assigned by TAPI to the line.
// We obtain it in TpOpenLine() from TAPI.
//
HTAPI_LINE htLine;
//
// This is the handle assigned by us to the line.
// We pass it to TAPI TpOpenLine().
//
// It is basically the index of the entry that points
// to the line context in pAdapter->TapiProv.LineTable
//
HDRV_LINE hdLine;
}
LINE;
typedef enum
_CALLSTATES
{
//
// Initial state
//
CL_stateIdle = 0,
//
// CLIENT states
//
CL_stateSendPadi, // Prepare a PADI packet and broadcast it
CL_stateWaitPado, // Wait for a PADO packet; timeout and broadcast PADI again if necesarry
CL_stateSendPadr, // PADO packet received and processed, prepare a PADR packet and send it to the peer
CL_stateWaitPads, // Wait for a PADS packet; timeout and resend the PADR packet if necesarry
//
// SERVER states
//
CL_stateRecvdPadr, // Received a PADR packet from the peer, and processing it.
// Once it is processed TAPI will be informed about the call.
//
CL_stateOffering, // TAPI is informaed about the call and call is waiting for an OID_TAPI_ANSWER
// from TAPI. If we do not get a an OID_TAPI_ANSWER in a timely manner, we time out
// and drop the call
//
CL_stateSendPads, // Call received a OID_TAPI_ANSWER from TAPI, so prepare a PADS packet and send it to
// the peer.
//
//
// CLIENT or SERVER states
//
CL_stateSessionUp, // Either sent or received a PADS packet and session is established
CL_stateDisconnected // Call is disconnected. Call may proceed to this state from any of the
// above states, it does not need to be connected first.
}
CALLSTATES;
//
// These identify the types of scheduled works:
//
// - CWT_workFsmMakeCall: This item is scheduled from TpMakeCall() to start making a call.
//
typedef enum
_CALL_WORKTYPE
{
CWT_workUnknown = 0,
CWT_workFsmMakeCall
}
CALL_WORKTYPE;
//
// This is our call call context.
// All information pertinent to a call is kept in this context.
//
typedef struct
_CALL
{
//
// Points to the next and previous call contexts in a double linked list
//
LIST_ENTRY linkCalls;
//
// Tag for the call control block (used for debugging).
//
ULONG tagCall;
//
// Keeps reference count on the call control block.
// References are added and deleted for the following operations:
//
// (a) A reference is added for running the initial FSM function for the call.
//
// (b) A reference is added for dropping the call, and removed when drop call
// is called.
//
// (c) A reference is added for closing the call, and removed when close call
// is called.
//
// (d) A reference is added when timers are set, and removed if timer expires,
// is cancelled or terminated.
//
// (e) When a packet is received to be dispatched, adapter context is locked,
// call context is found and referenced, adapter is unlocked and FSM function
// is called.
//
// (f) For any other operation not listed here, programmer should do as in (e).
//
LONG lRef;
//
// Spin lock to synchronize access to shared members
//
NDIS_SPIN_LOCK lockCall;
//
// Indicates the calls PPPoE state
//
CALLSTATES stateCall;
//
// Indicates that the call is initiated from another machine, and this machine is acting as
// a server.
//
BOOLEAN fIncoming;
//
// These are the various bit flags to indicate other state information for the call:
//
// (a) CLBF_CallIdle: This is the initial state of the call.
//
// (b) CLBF_CallOpen: This flag is indicates that the call context is opened.
// When a call context is created it is always created with CLBF_CallOpen
// and CLBF_CallConnectPending flags set, then if call connects succesfully,
// CLBF_CallConnectPending flag is reset, and only CLBF_CallOpen is left.
//
// The following pending flags might be set additionally:
// CLBF_CallConnectPending : If this flag is set the call is still connecting.
// Otherwise it means that the call is connected, and
// can make data over the link.
//
// (c) CLBF_CallConnectPending: This flag may be set only if CLBF_CallOpen is set. It means that
// the call is still in connect pending state. You can look at pCall->stateCall
// variable to retrieve the actual state of the call.
//
// (d) CLBF_CallDropped: This flag is set when call is dropped (disconnected).
// The following pending flags might be set additionally:
// CLBF_CallClosePending
//
// (e) CLBF_CallClosePending: This flag is set after the call is dropped and context is being cleared to
// be freed.
//
// (f) CLBF_CallClosed: This flag is set when call is closed (resources ready to be freed).
// No pending flags might be set when this bit is set.
//
//
//
// (g) CLBF_NotifyNDIS: This flag indicates that an asynchronous completion of a close call request
// must be communicated to NDIS using NdisMSetInformationComplete().
//
// (h) CLBF_CallReceivePacketHandlerScheduled: This flag indicates that the MpIndicateReceivedPackets()
// is scheduled to indicate packets in the receive queue.
//
ULONG ulClFlags;
#define CLBF_CallIdle 0x00000000
#define CLBF_CallOpen 0x00000001
#define CLBF_CallConnectPending 0x00000002
#define CLBF_CallDropped 0x00000004
#define CLBF_CallClosePending 0x00000008
#define CLBF_CallClosed 0x00000010
#define CLBF_NotifyNDIS 0x00000020
#define CLBF_CallReceivePacketHandlerScheduled 0x00000040
//
// Back pointer to the owning line context
//
LINE* pLine;
//
// This is the handle assigned by TAPI to the call.
// We obtain it in TpMakeCall() or TpAnswerCall() from TAPI.
//
HTAPI_CALL htCall;
//
// This is the handle assigned by us to the call.
// We obtain this when we create the call context and pass it back to TAPI
// either in return from TpMakeCall() or TpReceiveCall().
//
// This handle forms of 2 USHORT values appended.
// The higher 16 bits represent the index to the pAdapter->TapiProv.hCallTable, and
// the lower 16 bits is just a unique number generated everytime a call handle is created.
//
// This ensures the uniqueness of handles to avoid pitfalls that could result due to some weird
// timing conditions.
//
HDRV_CALL hdCall;
//
// This gives the link speed. It is obtained from the underlying binding context when
// call is attached to the binding.
//
ULONG ulSpeed;
//
// This is the max frame size for the underlying binding context.
// Passed to the call context in PrAddCallToBinding().
//
ULONG ulMaxFrameSize;
//
// This keeps TAPI's states. Its values are from LINECALLSTATE_ constants in SDK.
//
// States supported by us are:
// - LINECALLSTATE_IDLE
// - LINECALLSTATE_OFFERING
// - LINECALLSTATE_DIALING
// - LINECALLSTATE_PROCEEDING
// - LINECALLSTATE_CONNECTED
// - LINECALLSTATE_DISCONNECTED
//
ULONG ulTapiCallState;
#define TAPI_LINECALLSTATES_SUPPORTED ( LINECALLSTATE_IDLE | \
LINECALLSTATE_OFFERING | \
LINECALLSTATE_DIALING | \
LINECALLSTATE_PROCEEDING | \
LINECALLSTATE_CONNECTED | \
LINECALLSTATE_DISCONNECTED )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++
Link info needed by NDISWAN
typedef struct _NDIS_WAN_GET_LINK_INFO {
IN NDIS_HANDLE NdisLinkHandle;
OUT ULONG MaxSendFrameSize;
OUT ULONG MaxRecvFrameSize;
OUT ULONG HeaderPadding;
OUT ULONG TailPadding;
OUT ULONG SendFramingBits;
OUT ULONG RecvFramingBits;
OUT ULONG SendCompressionBits;
OUT ULONG RecvCompressionBits;
OUT ULONG SendACCM;
OUT ULONG RecvACCM;
} NDIS_WAN_GET_LINK_INFO, *PNDIS_WAN_GET_LINK_INFO;
typedef struct _NDIS_WAN_SET_LINK_INFO {
IN NDIS_HANDLE NdisLinkHandle;
IN ULONG MaxSendFrameSize;
IN ULONG MaxRecvFrameSize;
ULONG HeaderPadding;
ULONG TailPadding;
IN ULONG SendFramingBits;
IN ULONG RecvFramingBits;
IN ULONG SendCompressionBits;
IN ULONG RecvCompressionBits;
IN ULONG SendACCM;
IN ULONG RecvACCM;
} NDIS_WAN_SET_LINK_INFO, *PNDIS_WAN_SET_LINK_INFO;
-------------------------------------------------------*/
NDIS_WAN_GET_LINK_INFO NdisWanLinkInfo;
//
// This is the string that holds the service-name for the call.
// It must be an UTF-8 string per PPPoE RFC.
//
// We either obtain it in TpMakeCall() as the phone-number to dial, or
// receive it from the peer for an incoming call.
//
CHAR ServiceName[MAX_SERVICE_NAME_LENGTH];
//
// Indicates the length of the service name string
//
USHORT nServiceNameLength;
//
// This is the string that holds the AC-name for this call.
// It must be an UTF-8 string per PPPoE RFC.
//
// For an outgoing call, we obtain it from the adapter's context,
// for an incoming call we get it from PADO packet server sends.
//
CHAR ACName[MAX_AC_NAME_LENGTH];
//
// Indicates the length of the AC name string
//
USHORT nACNameLength;
//
// Indicates if ACName was specified by the caller or not
//
BOOLEAN fACNameSpecified;
//
// Peer's MAC address, obtained either when we receive or send a PADO packet
//
CHAR DestAddr[6];
//
// Our MAC address, obtained from binding in PrAddCallToBinding()
//
CHAR SrcAddr[6];
//
// Indicates the session id for the call.
//
// As per PPPoE RFC, a call is identified uniquely by the peer's MAC addresses plus a session id.
// In this implementation, we do not really care about the peer's MAC addresses, so we always
// make a unique session id. This is partly why we do not support both client and server functionality
// on the same box at the same time.
//
// For an incoming call, session id is selected as the index into pAdapter->TapiProv.hCallTable, and
// for an outgoing call it is assigned by the peer so we just traverse active calls to identify the
// correct call (which is very inefficient by the way, but this was a design decision that was discussed
// and approved by the PMs - the main scenario is that most people will not have many outgoing calls -
// anyway ).
//
USHORT usSessionId;
//
// Pointer to the binding context that the call is running over
//
BINDING* pBinding;
//
// Handle assigned to this peer-to-peer link by NDISWAN.
//
// This value is passed to us in NDIS_MAC_LINE_UP.
// We indicate anything to NDISWAN using this handle.
//
NDIS_HANDLE NdisLinkContext;
//
// This points to the last PPPoE control packet sent to the peer.
//
// This is necesarry for resending the packet on a timeout condition
// when we do not get a reply.
//
PPPOE_PACKET* pSendPacket;
//
// This is a special queue added to fix bug 172298 in Windows Bugs database.
// The problem is that the payload packets received right after a PADS but before contexts are exchanged
// with NDISWAN are dropped, and this causes a disturbing user experience.
//
// So I decided to change the packet receive mechanism. Instead I will queue up the packets and
// use a timer to indicate them to NDISWAN. I prefered timers instead of scheduling a work item because
// timers are more reliable than work items in terms of when to run.
//
LIST_ENTRY linkReceivedPackets;
//
// The maximum length of the queue
//
#define MAX_RECEIVED_PACKETS 100
//
// Number of packets in the received packet queue.
// The value can not exceed MAX_RECEIVED_PACKETS
//
ULONG nReceivedPackets;
//
// This will be used to indicate the packets in the receive queue to NDISWAN
//
TIMERQITEM timerReceivedPackets;
//
// The maximum number of packets to be indicated from the queue in one function call.
// If there are more items in the queue, we should schedule another timer.
//
#define MAX_INDICATE_RECEIVED_PACKETS 100
#define RECEIVED_PACKETS_TIMEOUT 1
//
// This is the timer queue item we use for this call.
//
TIMERQITEM timerTimeout;
//
// Indicates the number of timeouts occured.
// Max number of time outs is kept in pAdapter->nMaxTimeouts and is read from registry.
//
UINT nNumTimeouts;
}
CALL;
////////////////////////////////////
//
// Local macros
//
////////////////////////////////////
#define ALLOC_ADAPTER( ppA ) NdisAllocateMemoryWithTag( (PVOID*) ppA, sizeof( ADAPTER ), MTAG_ADAPTER )
#define FREE_ADAPTER( pA ) NdisFreeMemory( (PVOID) pA, sizeof( ADAPTER ), 0 );
#define VALIDATE_ADAPTER( pA ) ( (pA) && (pA->tagAdapter == MTAG_ADAPTER) )
VOID
CreateUniqueValue(
IN HDRV_CALL hdCall,
OUT CHAR* pUniqueValue,
OUT USHORT* pSize
);
VOID
ReferenceAdapter(
IN ADAPTER* pAdapter,
IN BOOLEAN fAcquireLock
);
VOID DereferenceAdapter(
IN ADAPTER* pAdapter
);
VOID
MpNotifyBindingRemoval(
BINDING* pBinding
);
VOID
MpRecvPacket(
IN BINDING* pBinding,
IN PPPOE_PACKET* pPacket
);
VOID
MpIndicateReceivedPackets(
IN TIMERQITEM* pTqi,
IN VOID* pContext,
IN TIMERQEVENT event
);
VOID
MpScheduleIndicateReceivedPacketsHandler(
CALL* pCall
);
NDIS_STATUS
MpWanGetInfo(
IN ADAPTER* pAdapter,
IN PNDIS_WAN_INFO pWanInfo
);
NDIS_STATUS
MpWanGetLinkInfo(
IN ADAPTER* pAdapter,
IN PNDIS_WAN_GET_LINK_INFO pWanLinkInfo
);
NDIS_STATUS
MpWanSetLinkInfo(
IN ADAPTER* pAdapter,
IN PNDIS_WAN_SET_LINK_INFO pWanLinkInfo
);
//////////////////////////////////////////////////////////////
//
// Interface prototypes: Functions exposed from this module
//
//////////////////////////////////////////////////////////////
NDIS_STATUS
MpRegisterMiniport(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath,
OUT NDIS_HANDLE* pNdisWrapperHandle
);
// These basics are not in the DDK headers for some reason.
//
#define min( a, b ) (((a) < (b)) ? (a) : (b))
#define max( a, b ) (((a) > (b)) ? (a) : (b))
#define InsertBefore( pNewL, pL ) \
{ \
(pNewL)->Flink = (pL); \
(pNewL)->Blink = (pL)->Blink; \
(pNewL)->Flink->Blink = (pNewL); \
(pNewL)->Blink->Flink = (pNewL); \
}
#define InsertAfter( pNewL, pL ) \
{ \
(pNewL)->Flink = (pL)->Flink; \
(pNewL)->Blink = (pL); \
(pNewL)->Flink->Blink = (pNewL); \
(pNewL)->Blink->Flink = (pNewL); \
}
// Pad to the size of the given datatype. (Borrowed from wdm.h which is not
// otherwise needed)
//
#define ALIGN_DOWN(length, type) \
((ULONG)(length) & ~(sizeof(type) - 1))
#define ALIGN_UP(length, type) \
(ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))
// Place in a TRACE argument list to correspond with a format of "%d" to print
// a percentage of two integers, or an average of two integers, or those
// values rounded.
//
#define PCTTRACE( n, d ) ((d) ? (((n) * 100) / (d)) : 0)
#define AVGTRACE( t, c ) ((c) ? ((t) / (c)) : 0)
#define PCTRNDTRACE( n, d ) ((d) ? (((((n) * 1000) / (d)) + 5) / 10) : 0)
#define AVGRNDTRACE( t, c ) ((c) ? (((((t) * 10) / (c)) + 5) / 10) : 0)
// All memory allocations and frees are done with these ALLOC_*/FREE_*
// macros/inlines to allow memory management scheme changes without global
// editing. For example, might choose to lump several lookaside lists of
// nearly equal sized items into a single list for efficiency.
//
// NdisFreeMemory requires the length of the allocation as an argument. NT
// currently doesn't use this for non-paged memory, but according to JameelH,
// Windows95 does. These inlines stash the length at the beginning of the
// allocation, providing the traditional malloc/free interface. The
// stash-area is a ULONGLONG so that all allocated blocks remain ULONGLONG
// aligned as they would be otherwise, preventing problems on Alphas.
//
__inline
VOID*
ALLOC_NONPAGED(
IN ULONG ulBufLength,
IN ULONG ulTag )
{
CHAR* pBuf;
NdisAllocateMemoryWithTag(
&pBuf, (UINT )(ulBufLength + MEMORY_ALLOCATION_ALIGNMENT), ulTag );
if (!pBuf)
{
return NULL;
}
((ULONG* )pBuf)[ 0 ] = ulBufLength;
((ULONG* )pBuf)[ 1 ] = 0xC0BBC0DE;
return pBuf + MEMORY_ALLOCATION_ALIGNMENT;
}
__inline
VOID
FREE_NONPAGED(
IN VOID* pBuf )
{
ULONG ulBufLen;
ulBufLen = *((ULONG* )(((CHAR* )pBuf) - MEMORY_ALLOCATION_ALIGNMENT));
NdisFreeMemory(
((CHAR* )pBuf) - MEMORY_ALLOCATION_ALIGNMENT,
(UINT )(ulBufLen + MEMORY_ALLOCATION_ALIGNMENT),
0 );
}
#define ALLOC_NDIS_WORK_ITEM( pWorkItemLookasideList ) \
NdisAllocateFromNPagedLookasideList( pWorkItemLookasideList )
#define FREE_NDIS_WORK_ITEM( pA, pNwi ) \
NdisFreeToNPagedLookasideList( pWorkItemLookasideList, (pNwi) )
#endif