diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/isn/flt/filter.c | 856 |
1 files changed, 856 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/flt/filter.c b/private/ntos/tdi/isn/flt/filter.c new file mode 100644 index 000000000..198f4addf --- /dev/null +++ b/private/ntos/tdi/isn/flt/filter.c @@ -0,0 +1,856 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + ntos\tdi\isn\flt\filter.c + +Abstract: + IPX Filter driver filtering and maintanance routines + + +Author: + + Vadim Eydelman + +Revision History: + +--*/ + +#include "precomp.h" + + // Masks to test components of the filter descriptor + // (Have to use globals in lue of constants to get correct + // byte ordering) +const union { + struct { + UCHAR Src[4]; + UCHAR Dst[4]; + } FD_Network; + ULONGLONG FD_NetworkSrcDst; + } FltSrcNetMask = {{{0xFF, 0xFF, 0xFF, 0xFF}, {0, 0, 0, 0}}}; +#define FLT_SRC_NET_MASK FltSrcNetMask.FD_NetworkSrcDst + +const union { + struct { + UCHAR Src[4]; + UCHAR Dst[4]; + } FD_Network; + ULONGLONG FD_NetworkSrcDst; + } FltDstNetMask = {{{0, 0, 0, 0}, {0xFF, 0xFF, 0xFF, 0xFF}}}; +#define FLT_DST_NET_MASK FltDstNetMask.FD_NetworkSrcDst + +const union { + struct { + UCHAR Node[6]; + UCHAR Socket[2]; + } FD_NS; + ULONGLONG FD_NodeSocket; + } FltNodeMask = {{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0, 0}}}; +#define FLT_NODE_MASK FltNodeMask.FD_NodeSocket + +const union { + struct { + UCHAR Node[6]; + UCHAR Socket[2]; + } FD_NS; + ULONGLONG FD_NodeSocket; + } FltSocketMask = {{{0, 0, 0, 0, 0, 0}, {0xFF, 0xFF}}}; +#define FLT_SOCKET_MASK FltSocketMask.FD_NodeSocket + + // Hash tables of interface control blocks with filter descriptions + // Input filters +LIST_ENTRY InterfaceInHash[FLT_INTERFACE_HASH_SIZE]; + // Output filters +LIST_ENTRY InterfaceOutHash[FLT_INTERFACE_HASH_SIZE]; + // Serializes access to interface table +FAST_MUTEX InterfaceTableLock; +LIST_ENTRY LogIrpQueue; +USHORT LogSeqNum; + + + // Hash function for interface hash tables +#define InterfaceIndexHash(Index) (Index%FLT_INTERFACE_HASH_SIZE) + + // Packet descriptor block +typedef struct _PACKET_DESCR { + union { + struct { + ULONG Src; // Source network + ULONG Dst; // Destination network + } PD_Network; + ULONGLONG PD_NetworkSrcDst; // Combined field + }; + ULONGLONG PD_SrcNodeSocket; // Source node & socket + ULONGLONG PD_DstNodeSocket; // Destination node & socket + LONG PD_ReferenceCount; // Filter reference count + UCHAR PD_PacketType; // Packet type + BOOLEAN PD_LogMatches; +} PACKET_DESCR, *PPACKET_DESCR; + + // Packet cache (only though that pass the filter) +PPACKET_DESCR PacketCache[FLT_PACKET_CACHE_SIZE]; +KSPIN_LOCK PacketCacheLock; + + +/*++ + A c q u i r e P a c k e t R e f e r e n c e + +Routine Description: + + Returns reference to the packet descriptor in the cache + +Arguments: + idx - cache index + pd - pointer to packet descriptor to be returned + +Return Value: + None + +--*/ +//VOID +//AcquirePacketReference ( +// IN UINT idx, +// OUT PPACKET_DESCR pd +// ); +#define AcquirePacketReference(idx,pd) { \ + KIRQL oldIRQL; \ + KeAcquireSpinLock (&PacketCacheLock, &oldIRQL); \ + if ((pd=PacketCache[idx])!=NULL) \ + InterlockedIncrement (&pd->PD_ReferenceCount); \ + KeReleaseSpinLock (&PacketCacheLock, oldIRQL); \ +} + +/*++ + R e l e a s e P a c k e t R e f e r e n c e + +Routine Description: + + Releases reference to the cached packet descriptor + +Arguments: + pd - pointer to packet descriptor to release + +Return Value: + None + +--*/ +//VOID +//ReleasePacketReference ( +// IN PPACKET_DESCR pd +// ); +#define ReleasePacketReference(pd) { \ + if (InterlockedDecrement (&pd->PD_ReferenceCount)>=0) \ + NOTHING; \ + else \ + ExFreePool (pd); \ +} + +/*++ + R e p l a c e P a c k e t R e f e r e n c e + +Routine Description: + + Replaces packet cache entry + +Arguments: + idx - cache index + pd - pointer to packet descriptor to be installed in the cache + +Return Value: + None + +--*/ +//VOID +//ReplacePacket ( +// IN UINT idx, +// IN PPACKET_DESCR pd +// ); +#define ReplacePacket(idx,pd) { \ + KIRQL oldIRQL; \ + PPACKET_DESCR oldPD; \ + KeAcquireSpinLock (&PacketCacheLock, &oldIRQL); \ + oldPD = PacketCache[idx]; \ + PacketCache[idx] = pd; \ + KeReleaseSpinLock (&PacketCacheLock, oldIRQL); \ + IpxFltDbgPrint (DBG_PKTCACHE, \ + ("IpxFlt: Replaced packet descriptor %08lx" \ + " with %08lx in cache at index %ld.\n", \ + oldPD, pd, idx)); \ + if (oldPD!=NULL) { \ + ReleasePacketReference(oldPD); \ + } \ +} + + // Defined below +VOID +FlushPacketCache ( + VOID + ); + +/*++ + I n i t i a l i z e T a b l e s + +Routine Description: + + Initializes hash and cash tables and protection stuff +Arguments: + None +Return Value: + STATUS_SUCCESS + +--*/ +NTSTATUS +InitializeTables ( + VOID + ) { + UINT i; + for (i=0; i<FLT_INTERFACE_HASH_SIZE; i++) { + InitializeListHead (&InterfaceInHash[i]); + InitializeListHead (&InterfaceOutHash[i]); + } + + for (i=0; i<FLT_PACKET_CACHE_SIZE; i++) { + PacketCache[i] = NULL; + } + KeInitializeSpinLock (&PacketCacheLock); + ExInitializeFastMutex (&InterfaceTableLock); + InitializeListHead (&LogIrpQueue); + LogSeqNum = 0; + return STATUS_SUCCESS; +} + +/*++ + D e l e t e T a b l e s + +Routine Description: + + Deletes hash and cash tables +Arguments: + None +Return Value: + None + +--*/ +VOID +DeleteTables ( + VOID + ) { + UINT i; + + for (i=0; i<FLT_INTERFACE_HASH_SIZE; i++) { + while (!IsListEmpty (&InterfaceInHash[i])) { + NTSTATUS status; + PINTERFACE_CB ifCB = CONTAINING_RECORD (InterfaceInHash[i].Flink, + INTERFACE_CB, ICB_Link); + status = FwdSetFilterInContext (ifCB->ICB_Index, NULL); + ASSERT (status==STATUS_SUCCESS); + RemoveEntryList (&ifCB->ICB_Link); + ExFreePool (ifCB); + } + while (!IsListEmpty (&InterfaceOutHash[i])) { + NTSTATUS status; + PINTERFACE_CB ifCB = CONTAINING_RECORD (InterfaceOutHash[i].Flink, + INTERFACE_CB, ICB_Link); + status = FwdSetFilterOutContext (ifCB->ICB_Index, NULL); + ASSERT (status==STATUS_SUCCESS); + RemoveEntryList (&ifCB->ICB_Link); + ExFreePool (ifCB); + } + } + for (i=0; i<FLT_PACKET_CACHE_SIZE; i++) { + if (PacketCache[i] != NULL) + ExFreePool (PacketCache[i]); + } + return ; +} + + +/*++ + S e t F i l t e r s + +Routine Description: + + Sets/replaces filter information for an interface +Arguments: + HashTable - input or output hash table + Index - interface index + FilterAction - default action if there is no filter match + FilterInfoSize - size of the info array + FilterInfo - array of filter descriptions (UI format) +Return Value: + STATUS_SUCCESS - filter info was set/replaced ok + STATUS_UNSUCCESSFUL - could not set filter context in forwarder + STATUS_INSUFFICIENT_RESOURCES - not enough memory to allocate + filter info block for interface + +--*/ +NTSTATUS +SetFilters ( + IN PLIST_ENTRY HashTable, + IN ULONG Index, + IN ULONG FilterAction, + IN ULONG FilterInfoSize, + IN PIPX_TRAFFIC_FILTER_INFO FilterInfo + ) { + PINTERFACE_CB ifCB = NULL, oldCB = NULL; + ULONG FilterCount + = FilterInfoSize/sizeof (IPX_TRAFFIC_FILTER_INFO); + ULONG i; + PFILTER_DESCR fd; + PLIST_ENTRY HashBucket = &HashTable[InterfaceIndexHash(Index)], cur; + NTSTATUS status = STATUS_SUCCESS; + + if (FilterCount>0) { + ifCB = ExAllocatePoolWithTag ( + NonPagedPool, + FIELD_OFFSET (INTERFACE_CB, ICB_Filters[FilterCount]), + IPX_FLT_TAG + ); + if (ifCB==NULL) { + IpxFltDbgPrint (DBG_IFHASH|DBG_ERRORS, + ("IpxFlt: Could not allocate interface CB for if %ld.\n", + Index)); + return STATUS_INSUFFICIENT_RESOURCES; + } + + ifCB->ICB_Index = Index; + ifCB->ICB_FilterAction = (FilterAction==IPX_TRAFFIC_FILTER_ACTION_PERMIT) + ? FILTER_PERMIT : FILTER_DENY; + ifCB->ICB_FilterCount = FilterCount; + // Copy/Map UI filters to the internal format + for (i=0, fd = ifCB->ICB_Filters; i<FilterCount; i++, fd++, FilterInfo++) { + if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_SRCNET) { + memcpy (fd->FD_Network.Src, FilterInfo->SourceNetwork, 4); + memcpy (fd->FD_NetworkMask.Src, FilterInfo->SourceNetworkMask, 4); + } + else { + memset (fd->FD_Network.Src, 0, 4); + memset (fd->FD_NetworkMask.Src, 0, 4); + } + + if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_DSTNET) { + memcpy (fd->FD_Network.Dst, FilterInfo->DestinationNetwork, 4); + memcpy (fd->FD_NetworkMask.Dst, FilterInfo->DestinationNetworkMask, 4); + } + else { + memset (fd->FD_Network.Dst, 0, 4); + memset (fd->FD_NetworkMask.Dst, 0, 4); + } + + if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_SRCNODE) { + memcpy (fd->FD_SrcNS.Node, FilterInfo->SourceNode, 6); + memset (fd->FD_SrcNSMask.Node, 0xFF, 6); + } + else { + memset (fd->FD_SrcNS.Node, 0, 6); + memset (fd->FD_SrcNSMask.Node, 0, 6); + } + + if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_SRCSOCKET) { + memcpy (fd->FD_SrcNS.Socket, FilterInfo->SourceSocket, 2); + memset (fd->FD_SrcNSMask.Socket, 0xFF, 2); + } + else { + memset (fd->FD_SrcNS.Socket, 0, 2); + memset (fd->FD_SrcNSMask.Socket, 0, 2); + } + + if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_DSTNODE) { + memcpy (fd->FD_DstNS.Node, FilterInfo->DestinationNode, 6); + memset (fd->FD_DstNSMask.Node, 0xFF, 6); + } + else { + memset (fd->FD_DstNS.Node, 0, 6); + memset (fd->FD_DstNSMask.Node, 0, 6); + } + + if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_DSTSOCKET) { + memcpy (fd->FD_DstNS.Socket, FilterInfo->DestinationSocket, 2); + memset (fd->FD_DstNSMask.Socket, 0xFF, 2); + } + else { + memset (fd->FD_DstNS.Socket, 0, 2); + memset (fd->FD_DstNSMask.Socket, 0, 2); + } + if (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_ON_PKTTYPE) { + fd->FD_PacketType = FilterInfo->PacketType; + fd->FD_PacketTypeMask = 0xFF; + } + else { + fd->FD_PacketType = 0; + fd->FD_PacketTypeMask = 0; + } + + fd->FD_LogMatches = (FilterInfo->FilterDefinition&IPX_TRAFFIC_FILTER_LOG_MATCHES)!=0; + } + } + + ExAcquireFastMutex (&InterfaceTableLock); + + // Find the old block and/or a place for a new one + cur = HashBucket->Flink; + while (cur!=HashBucket) { + oldCB = CONTAINING_RECORD (cur, INTERFACE_CB, ICB_Link); + if (oldCB->ICB_Index==Index) { + // Found the old one, place new after it + cur = cur->Flink; + break; + } + else if (oldCB->ICB_Index>Index) { + // No chance to see the old one anymore, place where + // we are now + oldCB = NULL; + break; + } + cur = cur->Flink; + } + + // Set context in forwarder + if (HashTable==InterfaceInHash) { + status = FwdSetFilterInContext (Index, ifCB); + } + else { + ASSERT (HashTable==InterfaceOutHash); + status = FwdSetFilterOutContext (Index, ifCB); + } + + if (NT_SUCCESS (status)) { + // Update table if we succeded + IpxFltDbgPrint (DBG_IFHASH, + ("IpxFlt: Set filters for if %ld (ifCB:%08lx).\n", + Index, ifCB)); + + if (oldCB!=NULL) { + IpxFltDbgPrint (DBG_IFHASH, + ("IpxFlt: Deleting replaced filters for if %ld (ifCB:%08lx).\n", + Index, oldCB)); + RemoveEntryList (&oldCB->ICB_Link); + ExFreePool (oldCB); + } + + + + if (ifCB!=NULL) { + InsertTailList (cur, &ifCB->ICB_Link); + } + + FlushPacketCache (); + } + else { + IpxFltDbgPrint (DBG_IFHASH|DBG_ERRORS, + ("IpxFlt: Failed to set context for if %ld (ifCB:%08lx).\n", + Index, ifCB)); + } + + ExReleaseFastMutex (&InterfaceTableLock); + return status; +} + +/*++ + G e t F i l t e r s + +Routine Description: + + Gets filter information for an interface +Arguments: + HashTable - input or output hash table + Index - interface index + FilterAction - default action if there is no filter match + TotalSize - total memory required to hold all filter descriptions + FilterInfo - array of filter descriptions (UI format) + FilterInfoSize - on input: size of the info array + on output: size of the info placed in the array +Return Value: + STATUS_SUCCESS - filter info was returned ok + STATUS_BUFFER_OVERFLOW - array is not big enough to hold all + filter info, only placed the info that fit + +--*/ +NTSTATUS +GetFilters ( + IN PLIST_ENTRY HashTable, + IN ULONG Index, + OUT ULONG *FilterAction, + OUT ULONG *TotalSize, + OUT PIPX_TRAFFIC_FILTER_INFO FilterInfo, + IN OUT ULONG *FilterInfoSize + ) { + PINTERFACE_CB oldCB = NULL; + ULONG i, AvailBufCount = + (*FilterInfoSize)/sizeof (IPX_TRAFFIC_FILTER_INFO); + PFILTER_DESCR fd; + PLIST_ENTRY HashBucket = &HashTable[InterfaceIndexHash(Index)], cur; + NTSTATUS status = STATUS_SUCCESS; + + // Locate interface filters block + ExAcquireFastMutex (&InterfaceTableLock); + cur = HashBucket->Flink; + while (cur!=HashBucket) { + oldCB = CONTAINING_RECORD (cur, INTERFACE_CB, ICB_Link); + if (oldCB->ICB_Index==Index) { + cur = cur->Flink; + break; + } + else if (oldCB->ICB_Index>Index) { + oldCB = NULL; + break; + } + cur = cur->Flink; + } + + if (oldCB!=NULL) { + *FilterAction = IS_FILTERED(oldCB->ICB_FilterAction) + ? IPX_TRAFFIC_FILTER_ACTION_DENY + : IPX_TRAFFIC_FILTER_ACTION_PERMIT; + *TotalSize = oldCB->ICB_FilterCount*sizeof (IPX_TRAFFIC_FILTER_INFO); + // Copy/Map as many descriptors as fit + for (i=0, fd = oldCB->ICB_Filters; + (i<oldCB->ICB_FilterCount) && (i<AvailBufCount); + i++, fd++, FilterInfo++) { + FilterInfo->FilterDefinition = 0; + if (fd->FD_NetworkMaskSrcDst&FLT_SRC_NET_MASK) { + memcpy (FilterInfo->SourceNetwork, fd->FD_Network.Src, 4); + memcpy (FilterInfo->SourceNetworkMask, fd->FD_NetworkMask.Src, 4); + FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_SRCNET; + } + + if (fd->FD_NetworkMaskSrcDst&FLT_DST_NET_MASK) { + memcpy (FilterInfo->DestinationNetwork, fd->FD_Network.Dst, 4); + memcpy (FilterInfo->DestinationNetworkMask, fd->FD_NetworkMask.Dst, 4); + FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_DSTNET; + } + + if (fd->FD_SrcNodeSocketMask&FLT_NODE_MASK) { + memcpy (FilterInfo->SourceNode, fd->FD_SrcNS.Node, 6); + FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_SRCNODE; + } + + if (fd->FD_DstNodeSocketMask&FLT_NODE_MASK) { + memcpy (FilterInfo->DestinationNode, fd->FD_DstNS.Node, 6); + FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_DSTNODE; + } + + if (fd->FD_SrcNodeSocketMask&FLT_SOCKET_MASK) { + memcpy (FilterInfo->SourceSocket, fd->FD_SrcNS.Socket, 2); + FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_SRCSOCKET; + } + if (fd->FD_DstNodeSocketMask&FLT_SOCKET_MASK) { + memcpy (FilterInfo->DestinationSocket, fd->FD_DstNS.Socket, 2); + FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_DSTSOCKET; + } + if (fd->FD_PacketTypeMask&0xFF) { + FilterInfo->PacketType = fd->FD_PacketType; + FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_ON_PKTTYPE; + } + if (fd->FD_LogMatches) + FilterInfo->FilterDefinition |= IPX_TRAFFIC_FILTER_LOG_MATCHES; + } + + *FilterInfoSize = i*sizeof (IPX_TRAFFIC_FILTER_INFO); + + IpxFltDbgPrint (DBG_IFHASH, + ("IpxFlt: Returning %d filters (%d available)" + " for interface %d (ifCB: %08lx).\n", + i, oldCB->ICB_FilterCount, Index)); + if (i<oldCB->ICB_FilterCount) + status = STATUS_BUFFER_OVERFLOW; + ExReleaseFastMutex (&InterfaceTableLock); + } + else { + // No interface block -> we are passing all the packets + // unfiltered + ExReleaseFastMutex (&InterfaceTableLock); + IpxFltDbgPrint (DBG_IFHASH, + ("IpxFlt: No filters for interface %d.\n", Index)); + *FilterAction = IPX_TRAFFIC_FILTER_ACTION_PERMIT; + *TotalSize = 0; + *FilterInfoSize = 0; + } + return status; +} + + +VOID +LogPacket ( + IN PUCHAR ipxHdr, + IN ULONG ipxHdrLength, + IN PVOID ifInContext, + IN PVOID ifOutContext + ) { + PIRP irp; + PIO_STACK_LOCATION irpStack; + ULONG outBufLength; + PUCHAR outBuffer; + ULONG offset; + KIRQL cancelIRQL; + + IoAcquireCancelSpinLock (&cancelIRQL); + LogSeqNum += 1; + while (!IsListEmpty (&LogIrpQueue)) { + irp = CONTAINING_RECORD (LogIrpQueue.Flink,IRP,Tail.Overlay.ListEntry); + irpStack = IoGetCurrentIrpStackLocation(irp); + outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; + outBuffer = (PUCHAR)MmGetSystemAddressForMdl (irp->MdlAddress); + offset = (PUCHAR)ALIGN_UP (outBuffer+irp->IoStatus.Information, ULONG)-outBuffer; + if (offset+ipxHdrLength+FIELD_OFFSET (FLT_PACKET_LOG, Header)<outBufLength) { + PFLT_PACKET_LOG pLog = (PFLT_PACKET_LOG) (outBuffer+offset); + pLog->SrcIfIdx = ifInContext + ? ((PINTERFACE_CB)ifInContext)->ICB_Index + : -1; + pLog->DstIfIdx = ifOutContext + ? ((PINTERFACE_CB)ifOutContext)->ICB_Index + : -1; + pLog->DataSize = (USHORT)ipxHdrLength; + pLog->SeqNum = LogSeqNum; + memcpy (pLog->Header, ipxHdr, ipxHdrLength); + irp->IoStatus.Information = offset+FIELD_OFFSET (FLT_PACKET_LOG, Header[ipxHdrLength]); + if (irp->Tail.Overlay.ListEntry.Flink!=&LogIrpQueue) { + RemoveEntryList (&irp->Tail.Overlay.ListEntry); + IoSetCancelRoutine (irp, NULL); + irp->IoStatus.Status = STATUS_SUCCESS; + IoReleaseCancelSpinLock (cancelIRQL); + IpxFltDbgPrint (DBG_PKTLOGS, + ("IpxFlt: completing logging request" + " with %d bytes of data.\n", + irp->IoStatus.Information)); + IoCompleteRequest (irp, IO_NO_INCREMENT); + return; + } + else + break; + } + RemoveEntryList (&irp->Tail.Overlay.ListEntry); + IoSetCancelRoutine (irp, NULL); + irp->IoStatus.Status = STATUS_SUCCESS; + IoReleaseCancelSpinLock (cancelIRQL); + IpxFltDbgPrint (DBG_ERRORS|DBG_PKTLOGS, + ("IpxFlt: completing logging request" + " with %d bytes of data (not enough space).\n", + irp->IoStatus.Information)); + IoCompleteRequest (irp, IO_NO_INCREMENT); + IoAcquireCancelSpinLock (&cancelIRQL); + } + IoReleaseCancelSpinLock (cancelIRQL); +} + + +/*++ + F i l t e r + +Routine Description: + + Filters the packet supplied by the forwarder + +Arguments: + ipxHdr - pointer to packet header + ipxHdrLength - size of the header buffer (must be at least 30) + ifInContext - context associated with interface on which packet + was received + ifOutContext - context associated with interface on which packet + will be sent +Return Value: + FILTER_PERMIT - packet should be passed on by the forwarder + FILTER_DENY_IN - packet should be dropped because of input filter + FILTER_DENY_OUT - packet should be dropped because of output filter +--*/ +FILTER_ACTION +Filter ( + IN PUCHAR ipxHdr, + IN ULONG ipxHdrLength, + IN PVOID ifInContext, + IN PVOID ifOutContext + ) { + PACKET_DESCR pd; + FILTER_ACTION res = FILTER_PERMIT; + UINT idx; + + ASSERT (ipxHdrLength>=IPXH_HDRSIZE); + // Copy packet to aligned buffer + pd.PD_Network.Dst = *((UNALIGNED ULONG *)(ipxHdr+IPXH_DESTNET)); + pd.PD_Network.Src = *((UNALIGNED ULONG *)(ipxHdr+IPXH_SRCNET)); + pd.PD_DstNodeSocket = *((UNALIGNED ULONGLONG *)(ipxHdr+IPXH_DESTNODE)); + pd.PD_SrcNodeSocket = *((UNALIGNED ULONGLONG *)(ipxHdr+IPXH_SRCNODE)); + pd.PD_PacketType = *(ipxHdr+IPXH_PKTTYPE); + pd.PD_LogMatches = FALSE; + // We do not cache netbios broadcast + if (pd.PD_PacketType!=IPX_NETBIOS_TYPE) { + PPACKET_DESCR cachedPD; + // Get cached packet + idx = (UINT)((pd.PD_Network.Dst + +pd.PD_DstNodeSocket + +pd.PD_PacketType) + %FLT_PACKET_CACHE_SIZE); + AcquirePacketReference (idx, cachedPD); + if (cachedPD!=NULL) { + // Fast path: packet in the cache matches + if ((pd.PD_NetworkSrcDst==cachedPD->PD_NetworkSrcDst) + && (pd.PD_SrcNodeSocket==cachedPD->PD_SrcNodeSocket) + && (pd.PD_DstNodeSocket==cachedPD->PD_DstNodeSocket) + && (pd.PD_PacketType==cachedPD->PD_PacketType)) { + if (cachedPD->PD_LogMatches) + LogPacket (ipxHdr,ipxHdrLength,ifInContext,ifOutContext); + ReleasePacketReference (cachedPD); + return FILTER_PERMIT; + } + // Do not need cached packet anymore + ReleasePacketReference (cachedPD); + } + } + // Slow path: check all filters + if (ifInContext!=NO_FILTER_CONTEXT) { + PFILTER_DESCR fd, fdEnd; + // Read default result (no filter match) + res = NOT_FILTER_ACTION(((PINTERFACE_CB)ifInContext)->ICB_FilterAction); + fd = ((PINTERFACE_CB)ifInContext)->ICB_Filters; + fdEnd = &((PINTERFACE_CB)ifInContext)->ICB_Filters + [((PINTERFACE_CB)ifInContext)->ICB_FilterCount]; + while (fd<fdEnd) { + if ( ((pd.PD_NetworkSrcDst & fd->FD_NetworkMaskSrcDst) + == fd->FD_NetworkSrcDst) + && ((pd.PD_SrcNodeSocket & fd->FD_SrcNodeSocketMask) + == fd->FD_SrcNodeSocket) + && ((pd.PD_DstNodeSocket & fd->FD_DstNodeSocketMask) + == fd->FD_DstNodeSocket) + && ((pd.PD_PacketType & fd->FD_PacketTypeMask) + == fd->FD_PacketType) ) { + // Filter match: reverse the result + res = NOT_FILTER_ACTION(res); + if (fd->FD_LogMatches) { + pd.PD_LogMatches = TRUE; + LogPacket (ipxHdr,ipxHdrLength,ifInContext,ifOutContext); + } + break; + } + fd++; + } + // Return right away if told to drop + if (IS_FILTERED(res)) + return FILTER_DENY_IN; + } + + if (ifOutContext!=NO_FILTER_CONTEXT) { + PFILTER_DESCR fd, fdEnd; + // Read default result (no filter match) + res = NOT_FILTER_ACTION(((PINTERFACE_CB)ifOutContext)->ICB_FilterAction); + fd = ((PINTERFACE_CB)ifOutContext)->ICB_Filters; + fdEnd = &((PINTERFACE_CB)ifOutContext)->ICB_Filters + [((PINTERFACE_CB)ifOutContext)->ICB_FilterCount]; + while (fd<fdEnd) { + if ( ((pd.PD_NetworkSrcDst & fd->FD_NetworkMaskSrcDst) + == fd->FD_NetworkSrcDst) + && ((pd.PD_SrcNodeSocket & fd->FD_SrcNodeSocketMask) + == fd->FD_SrcNodeSocket) + && ((pd.PD_DstNodeSocket & fd->FD_DstNodeSocketMask) + == fd->FD_DstNodeSocket) + && ((pd.PD_PacketType & fd->FD_PacketTypeMask) + == fd->FD_PacketType) ) { + // Filter match: reverse the result + res = NOT_FILTER_ACTION(res); + if (fd->FD_LogMatches&&!pd.PD_LogMatches) { + pd.PD_LogMatches = TRUE; + LogPacket (ipxHdr,ipxHdrLength,ifInContext,ifOutContext); + } + break; + } + fd++; + } + // Return right away if told to drop + if (IS_FILTERED(res)) + return FILTER_DENY_OUT; + } + + // Cache the packet (we know that it is a pass + // because we would have returned if it was a drop) + if (pd.PD_PacketType!=IPX_NETBIOS_TYPE) { + PPACKET_DESCR cachedPD; + cachedPD = ExAllocatePoolWithTag ( + NonPagedPool, + sizeof (PACKET_DESCR), + IPX_FLT_TAG + ); + if (cachedPD!=NULL) { + *cachedPD = pd; + cachedPD->PD_ReferenceCount = 0; + ReplacePacket (idx, cachedPD); + } + } + + return res; +} + + +/*++ + I n t e r f a c e D e l e t e d + +Routine Description: + + Frees interface filters blocks when forwarder indicates that + interface is deleted +Arguments: + ifInContext - context associated with input filters block + ifOutContext - context associated with output filters block +Return Value: + None + +--*/ +VOID +InterfaceDeleted ( + IN PVOID ifInContext, + IN PVOID ifOutContext + ) { + IpxFltDbgPrint (DBG_FWDIF, + ("IpxFlt: InterfaceDeleted indication," + "(inContext: %08lx, outContext: %08lx).\n", + ifInContext, ifOutContext)); + ExAcquireFastMutex (&InterfaceTableLock); + if (ifInContext!=NULL) { + PINTERFACE_CB ifCB = (PINTERFACE_CB)ifInContext; + IpxFltDbgPrint (DBG_IFHASH, + ("IpxFlt: Deleting filters for if %ld (ifCB:%08lx)" + " on InterfaceDeleted indication from forwarder.\n", + ifCB->ICB_Index, ifCB)); + RemoveEntryList (&ifCB->ICB_Link); + ExFreePool (ifCB); + } + + if (ifOutContext!=NULL) { + PINTERFACE_CB ifCB = (PINTERFACE_CB)ifOutContext; + IpxFltDbgPrint (DBG_IFHASH, + ("IpxFlt: Deleting filters for if %ld (ifCB:%08lx)" + " on InterfaceDeleted indication from forwarder.\n", + ifCB->ICB_Index, ifCB)); + RemoveEntryList (&ifCB->ICB_Link); + ExFreePool (ifCB); + } + ExReleaseFastMutex (&InterfaceTableLock); + FlushPacketCache (); + return ; +} + +/*++ + F l u s h P a c k e t C a c h e + +Routine Description: + + Deletes all cached packet descriptions +Arguments: + None +Return Value: + None + +--*/ +VOID +FlushPacketCache ( + VOID + ) { + UINT i; + IpxFltDbgPrint (DBG_PKTCACHE, ("IpxFlt: Flushing packet chache.\n")); + for (i=0; i<FLT_PACKET_CACHE_SIZE; i++) { + ReplacePacket (i, NULL); + } +} + + + |