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.
482 lines
29 KiB
482 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nfilter.h
|
|
|
|
Abstract:
|
|
|
|
Header file for the address filtering library for NDIS MAC's.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (jameelh) July 1998
|
|
|
|
Environment:
|
|
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#ifndef _NULL_FILTER_DEFS_
|
|
#define _NULL_FILTER_DEFS_
|
|
|
|
typedef
|
|
VOID
|
|
(*NULL_DEFERRED_CLOSE)(
|
|
IN NDIS_HANDLE BindingHandle
|
|
);
|
|
|
|
//
|
|
// The binding info is threaded on a single list.
|
|
//
|
|
typedef X_BINDING_INFO NULL_BINDING_INFO,*PNULL_BINDING_INFO;
|
|
|
|
typedef X_FILTER NULL_FILTER,*PNULL_FILTER;
|
|
|
|
//
|
|
// Exported functions
|
|
//
|
|
EXPORT
|
|
BOOLEAN
|
|
nullCreateFilter(
|
|
OUT PNULL_FILTER * Filter
|
|
);
|
|
|
|
EXPORT
|
|
VOID
|
|
nullDeleteFilter(
|
|
IN PNULL_FILTER Filter
|
|
);
|
|
|
|
|
|
EXPORT
|
|
NDIS_STATUS
|
|
nullDeleteFilterOpenAdapter(
|
|
IN PNULL_FILTER Filter,
|
|
IN NDIS_HANDLE NdisFilterHandle
|
|
);
|
|
|
|
VOID
|
|
nullRemoveAndFreeBinding(
|
|
IN PNULL_FILTER Filter,
|
|
IN PNULL_BINDING_INFO Binding,
|
|
IN BOOLEAN fCallCloseAction
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
nullFilterLockHandler(
|
|
IN PNULL_FILTER Filter,
|
|
IN OUT PLOCK_STATE pLockState
|
|
);
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Multiple-reader-single-writer locking scheme for Filter DB
|
|
|
|
Use refCounts to keep track of how many readers are doing reads.
|
|
Use per-processor refCounts to reduce bus traffic.
|
|
Writers are serialized by means of a spin lock. Then they wait for
|
|
readers to finish reading by waiting till refCounts for all processors
|
|
go to zero. Rely on snoopy caches to get the sum right without doing
|
|
interlocked operations
|
|
|
|
--*/
|
|
|
|
#define TEST_SPIN_LOCK(_L) ((_L) != 0)
|
|
|
|
#define NDIS_READ_LOCK(_L, _pLS) \
|
|
{ \
|
|
UINT refcount; \
|
|
ULONG Prc; \
|
|
\
|
|
RAISE_IRQL_TO_DISPATCH(&(_pLS)->OldIrql); \
|
|
\
|
|
/* go ahead and bump up the ref count IF no writes are underway */ \
|
|
Prc = CURRENT_PROCESSOR; \
|
|
refcount = InterlockedIncrement((PLONG)&(_L)->RefCount[Prc].RefCount); \
|
|
\
|
|
/* Test if spin lock is held, i.e., write is underway */ \
|
|
/* if (KeTestSpinLock(&(_L)->SpinLock) == TRUE) */ \
|
|
/* This processor already is holding the lock, just */ \
|
|
/* allow him to take it again or else we run into a */ \
|
|
/* dead-lock situation with the writer */ \
|
|
if (TEST_SPIN_LOCK((_L)->SpinLock) && \
|
|
(refcount == 1) && \
|
|
((_L)->Context != CURRENT_THREAD)) \
|
|
{ \
|
|
(_L)->RefCount[Prc].RefCount--; \
|
|
ACQUIRE_SPIN_LOCK_DPC(&(_L)->SpinLock); \
|
|
(_L)->RefCount[Prc].RefCount++; \
|
|
RELEASE_SPIN_LOCK_DPC(&(_L)->SpinLock); \
|
|
} \
|
|
(_pLS)->LockState = READ_LOCK_STATE_FREE; \
|
|
}
|
|
|
|
|
|
#define NDIS_READ_LOCK_DPC(_L, _pLS) \
|
|
{ \
|
|
UINT refcount; \
|
|
ULONG Prc; \
|
|
\
|
|
/* go ahead and bump up the ref count IF no writes are underway */ \
|
|
Prc = CURRENT_PROCESSOR; \
|
|
refcount = InterlockedIncrement((PLONG)&(_L)->RefCount[Prc].RefCount); \
|
|
\
|
|
/* Test if spin lock is held, i.e., write is underway */ \
|
|
/* if (KeTestSpinLock(&(_L)->SpinLock) == TRUE) */ \
|
|
/* This processor already is holding the lock, just */ \
|
|
/* allow him to take it again or else we run into a */ \
|
|
/* dead-lock situation with the writer */ \
|
|
if (TEST_SPIN_LOCK((_L)->SpinLock) && \
|
|
(refcount == 1) && \
|
|
((_L)->Context != CURRENT_THREAD)) \
|
|
{ \
|
|
(_L)->RefCount[Prc].RefCount--; \
|
|
ACQUIRE_SPIN_LOCK_DPC(&(_L)->SpinLock); \
|
|
(_L)->RefCount[Prc].RefCount++; \
|
|
RELEASE_SPIN_LOCK_DPC(&(_L)->SpinLock); \
|
|
} \
|
|
(_pLS)->LockState = READ_LOCK_STATE_FREE; \
|
|
}
|
|
|
|
|
|
#define NDIS_WRITE_LOCK_STATE_UNKNOWN(_L, _pLS) \
|
|
{ \
|
|
UINT i, refcount; \
|
|
ULONG Prc; \
|
|
\
|
|
/* \
|
|
* This means we need to attempt to acquire the lock, \
|
|
* if we do not already own it. \
|
|
* Set the state accordingly. \
|
|
*/ \
|
|
if ((_L)->Context == CURRENT_THREAD) \
|
|
{ \
|
|
(_pLS)->LockState = LOCK_STATE_ALREADY_ACQUIRED; \
|
|
} \
|
|
else \
|
|
{ \
|
|
ACQUIRE_SPIN_LOCK(&(_L)->SpinLock, &(_pLS)->OldIrql); \
|
|
\
|
|
Prc = KeGetCurrentProcessorNumber(); \
|
|
refcount = (_L)->RefCount[Prc].RefCount; \
|
|
(_L)->RefCount[Prc].RefCount = 0; \
|
|
\
|
|
/* wait for all readers to exit */ \
|
|
for (i=0; i < ndisNumberOfProcessors; i++) \
|
|
{ \
|
|
volatile UINT *_p = &(_L)->RefCount[i].RefCount; \
|
|
\
|
|
while (*_p != 0) \
|
|
NDIS_INTERNAL_STALL(50); \
|
|
} \
|
|
\
|
|
(_L)->RefCount[Prc].RefCount = refcount; \
|
|
(_L)->Context = CURRENT_THREAD; \
|
|
(_pLS)->LockState = WRITE_LOCK_STATE_FREE; \
|
|
} \
|
|
}
|
|
|
|
#define NDIS_READ_LOCK_STATE_FREE(_L, _pLS) \
|
|
{ \
|
|
ULONG Prc; \
|
|
ASSERT(CURRENT_IRQL == DISPATCH_LEVEL); \
|
|
Prc = CURRENT_PROCESSOR; \
|
|
ASSERT((_L)->RefCount[Prc].RefCount > 0); \
|
|
(_L)->RefCount[Prc].RefCount--; \
|
|
(_pLS)->LockState = LOCK_STATE_UNKNOWN; \
|
|
if ((_pLS)->OldIrql < DISPATCH_LEVEL) \
|
|
{ \
|
|
KeLowerIrql((_pLS)->OldIrql); \
|
|
} \
|
|
}
|
|
|
|
#define NDIS_READ_LOCK_STATE_FREE_DPC(_L, _pLS) \
|
|
{ \
|
|
ULONG Prc; \
|
|
ASSERT(CURRENT_IRQL == DISPATCH_LEVEL); \
|
|
Prc = CURRENT_PROCESSOR; \
|
|
ASSERT((INT)(_L)->RefCount[Prc].RefCount > 0); \
|
|
(_L)->RefCount[Prc].RefCount--; \
|
|
(_pLS)->LockState = LOCK_STATE_UNKNOWN; \
|
|
}
|
|
|
|
#define NDIS_WRITE_LOCK_STATE_FREE(_L, _pLS) \
|
|
{ \
|
|
/* We acquired it. Now we need to free it */ \
|
|
ASSERT(CURRENT_IRQL == DISPATCH_LEVEL); \
|
|
ASSERT((_L)->Context == CURRENT_THREAD); \
|
|
(_pLS)->LockState = LOCK_STATE_UNKNOWN; \
|
|
(_L)->Context = NULL; \
|
|
RELEASE_SPIN_LOCK(&(_L)->SpinLock, (_pLS)->OldIrql); \
|
|
}
|
|
|
|
#define NDIS_LOCK_STATE_ALREADY_ACQUIRED(_L, _pLS) \
|
|
{ \
|
|
ASSERT((_L)->Context == CURRENT_THREAD); \
|
|
/* Nothing to do */ \
|
|
}
|
|
|
|
|
|
#define xLockHandler(_L, _pLS) \
|
|
{ \
|
|
switch ((_pLS)->LockState) \
|
|
{ \
|
|
case READ_LOCK: \
|
|
NDIS_READ_LOCK(_L, _pLS); \
|
|
break; \
|
|
\
|
|
case WRITE_LOCK_STATE_UNKNOWN: \
|
|
NDIS_WRITE_LOCK_STATE_UNKNOWN(_L, _pLS); \
|
|
break; \
|
|
\
|
|
case READ_LOCK_STATE_FREE: \
|
|
NDIS_READ_LOCK_STATE_FREE(_L, _pLS); \
|
|
break; \
|
|
\
|
|
case WRITE_LOCK_STATE_FREE: \
|
|
NDIS_WRITE_LOCK_STATE_FREE(_L, _pLS); \
|
|
break; \
|
|
\
|
|
case LOCK_STATE_ALREADY_ACQUIRED: \
|
|
NDIS_LOCK_STATE_ALREADY_ACQUIRED(_L, _pLS); \
|
|
/* Nothing to do */ \
|
|
break; \
|
|
\
|
|
default: \
|
|
ASSERT(0); \
|
|
break; \
|
|
} \
|
|
}
|
|
|
|
#define NDIS_INITIALIZE_RCVD_PACKET(_P, _NSR, _M) \
|
|
{ \
|
|
_NSR->RefCount = -1; \
|
|
_NSR->XRefCount = 0; \
|
|
_NSR->Miniport = _M; \
|
|
/* \
|
|
* Ensure that we force re-calculation. \
|
|
*/ \
|
|
(_P)->Private.ValidCounts = FALSE; \
|
|
}
|
|
|
|
#define NDIS_ACQUIRE_PACKET_LOCK_DPC(_NSR) ACQUIRE_SPIN_LOCK_DPC(&(_NSR)->Lock)
|
|
|
|
#define NDIS_RELEASE_PACKET_LOCK_DPC(_NSR) RELEASE_SPIN_LOCK_DPC(&(_NSR)->Lock)
|
|
|
|
#define ADJUST_PACKET_REFCOUNT(_NSR, _pRC) \
|
|
{ \
|
|
*(_pRC) = InterlockedDecrement(&(_NSR)->RefCount); \
|
|
}
|
|
|
|
#ifdef TRACK_RECEIVED_PACKETS
|
|
|
|
//
|
|
// NSR->XRefCount = Number of times protocol said it will call NdisReturnPacket
|
|
// NSR->RefCount = is decremented every time protocol calls NdisReturnPackets
|
|
//
|
|
|
|
#define COALESCE_PACKET_REFCOUNT_DPC(_Packet, _M, _NSR, _pOob, _pRC) \
|
|
{ \
|
|
LONG _LocalXRef = (_NSR)->XRefCount; \
|
|
if (_LocalXRef != 0) \
|
|
{ \
|
|
LONG _LocalRef; \
|
|
ASSERT((_pOob)->Status != NDIS_STATUS_RESOURCES); \
|
|
_LocalRef = InterlockedExchangeAdd(&(_NSR)->RefCount, (_LocalXRef + 1)); \
|
|
*(_pRC) = _LocalRef + _LocalXRef + 1; \
|
|
if ((*(_pRC) > 0) && (!MINIPORT_TEST_FLAG((_M), fMINIPORT_DESERIALIZE))) \
|
|
{ \
|
|
NDIS_SET_PACKET_STATUS(_Packet, NDIS_STATUS_PENDING); \
|
|
} \
|
|
if ((*(_pRC) == 0) && ((_NSR)->RefCount != 0)) \
|
|
{ \
|
|
DbgPrint("Packet %p is being returned back to the miniport" \
|
|
" but the ref count is not zero.\n", _Packet); \
|
|
DbgBreakPoint(); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
_NSR->RefCount = *(_pRC) = 0; \
|
|
} \
|
|
}
|
|
|
|
#define TACKLE_REF_COUNT(_M, _P, _S, _O) \
|
|
{ \
|
|
LONG RefCount; \
|
|
\
|
|
/* \
|
|
* We started off with the RefCount set to -1. \
|
|
* NdisReturnPackets may have been called which will further reduce it. \
|
|
* Add back the RefCount returned by the protocol \
|
|
* and account for the initial -1. \
|
|
*/ \
|
|
COALESCE_PACKET_REFCOUNT_DPC(_P, _M, _S, _O, &RefCount); \
|
|
\
|
|
NDIS_APPEND_RCV_LOGFILE(_P, _M, CurThread, \
|
|
7, OrgPacketStackLocation+1, _S->RefCount, _S->XRefCount, NDIS_GET_PACKET_STATUS(_P)); \
|
|
\
|
|
\
|
|
if (RefCount == 0) \
|
|
{ \
|
|
POP_PACKET_STACK(_P); \
|
|
if ((_O)->Status != NDIS_STATUS_RESOURCES) \
|
|
{ \
|
|
if (MINIPORT_TEST_FLAG((_M), fMINIPORT_DESERIALIZE)) \
|
|
{ \
|
|
/* \
|
|
* Return packets which are truly free, \
|
|
* but only for deserialized drivers \
|
|
*/ \
|
|
W_RETURN_PACKET_HANDLER Handler; \
|
|
if (_S->RefCount != 0) \
|
|
{ \
|
|
DbgPrint("Packet %p is being returned back to the " \
|
|
"miniport but the ref count is not zero.\n", _P); \
|
|
DbgBreakPoint(); \
|
|
} \
|
|
if ((_P)->Private.Head == NULL) \
|
|
{ \
|
|
DbgPrint("Packet %p is being returned back to the miniport with NULL Head.\n", _P); \
|
|
DbgBreakPoint(); \
|
|
} \
|
|
\
|
|
if (!MINIPORT_TEST_FLAG(_M, fMINIPORT_INTERMEDIATE_DRIVER)) \
|
|
{ \
|
|
ULONG SL; \
|
|
if ((SL = CURR_STACK_LOCATION(_P)) != -1) \
|
|
{ \
|
|
DbgPrint("Packet %p is being returned back to the non-IM miniport"\
|
|
" with stack location %lx.\n", Packet, SL); \
|
|
DbgBreakPoint(); \
|
|
} \
|
|
} \
|
|
\
|
|
Handler = (_M)->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;\
|
|
(_S)->Miniport = NULL; \
|
|
(_O)->Status = NDIS_STATUS_PENDING; \
|
|
\
|
|
NDIS_APPEND_RCV_LOGFILE(_P, _M, CurThread, \
|
|
8, OrgPacketStackLocation+1, _S->RefCount, _S->XRefCount, NDIS_GET_PACKET_STATUS(_P)); \
|
|
\
|
|
\
|
|
(*Handler)((_M)->MiniportAdapterContext, _P); \
|
|
} \
|
|
else \
|
|
{ \
|
|
{ \
|
|
ULONG SL; \
|
|
if ((SL = CURR_STACK_LOCATION(_P)) != -1) \
|
|
{ \
|
|
DbgPrint("Packet %p is being returned back to the non-IM miniport"\
|
|
" with stack location %lx.\n", Packet, SL); \
|
|
DbgBreakPoint(); \
|
|
} \
|
|
} \
|
|
\
|
|
if ((NDIS_GET_PACKET_STATUS(_P) == NDIS_STATUS_RESOURCES)) \
|
|
{ \
|
|
NDIS_STATUS _OStatus = (NDIS_STATUS)NDIS_PER_PACKET_INFO_FROM_PACKET(_P, OriginalStatus); \
|
|
\
|
|
if (_OStatus != NDIS_STATUS_RESOURCES) \
|
|
{ \
|
|
DbgPrint("Packet %p is being returned back to the non-deserialized miniport"\
|
|
" with packet status changed from %lx to NDIS_STATUS_RESOURCES.\n", _P, _OStatus); \
|
|
DbgBreakPoint(); \
|
|
} \
|
|
\
|
|
} \
|
|
\
|
|
(_O)->Status = NDIS_STATUS_SUCCESS; \
|
|
NDIS_APPEND_RCV_LOGFILE(_P, _M, CurThread, \
|
|
9, OrgPacketStackLocation+1, _S->RefCount, _S->XRefCount, NDIS_GET_PACKET_STATUS(_P)); \
|
|
\
|
|
} \
|
|
} \
|
|
} \
|
|
else if (MINIPORT_TEST_FLAG((_M), fMINIPORT_INTERMEDIATE_DRIVER)) \
|
|
{ \
|
|
InterlockedIncrement((PLONG)&(_M)->IndicatedPacketsCount); \
|
|
} \
|
|
}
|
|
|
|
#else
|
|
//
|
|
// NSR->XRefCount = Number of times protocol said it will call NdisReturnPacket
|
|
// NSR->RefCount = is decremented every time protocol calls NdisReturnPackets
|
|
//
|
|
|
|
#define COALESCE_PACKET_REFCOUNT_DPC(_Packet, _M, _NSR, _pOob, _pRC) \
|
|
{ \
|
|
LONG _LocalXRef = (_NSR)->XRefCount; \
|
|
if (_LocalXRef != 0) \
|
|
{ \
|
|
LONG _LocalRef; \
|
|
ASSERT((_pOob)->Status != NDIS_STATUS_RESOURCES); \
|
|
_LocalRef = InterlockedExchangeAdd(&(_NSR)->RefCount, (_LocalXRef + 1)); \
|
|
*(_pRC) = _LocalRef + _LocalXRef + 1; \
|
|
if ((*(_pRC) > 0) && (!MINIPORT_TEST_FLAG((_M), fMINIPORT_DESERIALIZE))) \
|
|
{ \
|
|
NDIS_SET_PACKET_STATUS(_Packet, NDIS_STATUS_PENDING); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
_NSR->RefCount = *(_pRC) = 0; \
|
|
} \
|
|
}
|
|
|
|
#define TACKLE_REF_COUNT(_M, _P, _S, _O) \
|
|
{ \
|
|
LONG RefCount; \
|
|
\
|
|
/* \
|
|
* We started off with the RefCount set to -1. \
|
|
* NdisReturnPackets may have been called which will further reduce it. \
|
|
* Add back the RefCount returned by the protocol \
|
|
* and account for the initial -1. \
|
|
*/ \
|
|
COALESCE_PACKET_REFCOUNT_DPC(_P, _M, _S, _O, &RefCount); \
|
|
\
|
|
if (RefCount == 0) \
|
|
{ \
|
|
POP_PACKET_STACK(_P); \
|
|
if ((_O)->Status != NDIS_STATUS_RESOURCES) \
|
|
{ \
|
|
if (MINIPORT_TEST_FLAG((_M), fMINIPORT_DESERIALIZE)) \
|
|
{ \
|
|
/* \
|
|
* Return packets which are truly free, \
|
|
* but only for deserialized drivers \
|
|
*/ \
|
|
W_RETURN_PACKET_HANDLER Handler; \
|
|
\
|
|
Handler = (_M)->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;\
|
|
(_S)->Miniport = NULL; \
|
|
(_O)->Status = NDIS_STATUS_PENDING; \
|
|
\
|
|
(*Handler)((_M)->MiniportAdapterContext, _P); \
|
|
} \
|
|
else \
|
|
{ \
|
|
(_O)->Status = NDIS_STATUS_SUCCESS; \
|
|
} \
|
|
} \
|
|
} \
|
|
else if (MINIPORT_TEST_FLAG((_M), fMINIPORT_INTERMEDIATE_DRIVER)) \
|
|
{ \
|
|
InterlockedIncrement((PLONG)&(_M)->IndicatedPacketsCount); \
|
|
} \
|
|
}
|
|
|
|
|
|
#endif
|
|
#endif // _NULL_FILTER_DEFS_
|