/*++ Copyright (c) 1990 Microsoft Corporation Module Name: tfilter.h Abstract: Header file for the address filtering library for NDIS MAC's. Author: Anthony V. Ercolano (tonye) creation-date 3-Aug-1990 Environment: Runs in the context of a single MAC driver. Notes: None. Revision History: Adam Barr (adamba) 19-Mar-1991 - Modified for Token-Ring --*/ #ifndef _TR_FILTER_DEFS_ #define _TR_FILTER_DEFS_ #define TR_LENGTH_OF_FUNCTIONAL 4 #define TR_LENGTH_OF_ADDRESS 6 // // Only the low 32 bits of the functional/group address // are needed since the upper 16 bits is always c0-00. // typedef ULONG TR_FUNCTIONAL_ADDRESS; typedef ULONG TR_GROUP_ADDRESS; // // #define TR_IS_NOT_DIRECTED(_Address, _Result) \ { \ *(_Result) = (BOOLEAN)((_Address)[0] & ((UCHAR)0x80));\ } // // #define TR_IS_FUNCTIONAL(_Address, _Result) \ { \ *(_Result) = (BOOLEAN)(((_Address)[0] & ((UCHAR)0x80)) &&\ !((_Address)[2] & ((UCHAR)0x80))); \ } // // #define TR_IS_GROUP(_Address, _Result) \ { \ *(_Result) = (BOOLEAN)((_Address)[0] & (_Address)[2] & ((UCHAR)0x80)); \ } // // #define TR_IS_SOURCE_ROUTING(_Address, _Result) \ { \ *(_Result) = (BOOLEAN)((_Address)[0] & 0x80); \ } // // Check for NDIS_PACKET_TYPE_MAC_FRAME // #define TR_IS_MAC_FRAME(_PacketHeader) \ ((((PUCHAR)_PacketHeader)[1] & 0xFC) == 0) // // Check whether an address is broadcast. This is a little-endian check. // #define TR_IS_BROADCAST(_Address, _Result) \ { \ *(_Result) = (BOOLEAN)(((*(UNALIGNED USHORT *)&(_Address)[0] == 0xFFFF) || \ (*(UNALIGNED USHORT *)&(_Address)[0] == 0x00C0)) && \ (*(UNALIGNED ULONG *)&(_Address)[2] == 0xFFFFFFFF)); \ } // // This macro will compare network addresses. // // A - Is a network address. // // B - Is a network address. // // Result - The result of comparing two network address. // // Result < 0 Implies the B address is greater. // Result > 0 Implies the A element is greater. // Result = 0 Implies equality. // // Note that this is an arbitrary ordering. There is not // defined relation on network addresses. This is ad-hoc! // // #define TR_COMPARE_NETWORK_ADDRESSES(_A, _B, _Result) \ { \ if (*(ULONG UNALIGNED *)&(_A)[2] > \ *(ULONG UNALIGNED *)&(_B)[2]) \ { \ *(_Result) = 1; \ } \ else if (*(ULONG UNALIGNED *)&(_A)[2] < \ *(ULONG UNALIGNED *)&(_B)[2]) \ { \ *(_Result) = (UINT)-1; \ } \ else if (*(USHORT UNALIGNED *)(_A) > \ *(USHORT UNALIGNED *)(_B)) \ { \ *(_Result) = 1; \ } \ else if (*(USHORT UNALIGNED *)(_A) < \ *(USHORT UNALIGNED *)(_B)) \ { \ *(_Result) = (UINT)-1; \ } \ else \ { \ *(_Result) = 0; \ } \ } // // This macro will compare network addresses. // // A - Is a network address. // // B - Is a network address. // // Result - The result of comparing two network address. // // Result != 0 Implies inequality. // Result == 0 Implies equality. // // #define TR_COMPARE_NETWORK_ADDRESSES_EQ(_A, _B, _Result) \ { \ if ((*(ULONG UNALIGNED *)&(_A)[2] == \ *(ULONG UNALIGNED *)&(_B)[2]) && \ (*(USHORT UNALIGNED *)(_A) == \ *(USHORT UNALIGNED *)(_B))) \ { \ *(_Result) = 0; \ } \ else \ { \ *(_Result) = 1; \ } \ } // // This macro is used to copy from one network address to // another. // #define TR_COPY_NETWORK_ADDRESS(_D, _S) \ { \ *((ULONG UNALIGNED *)(_D)) = *((ULONG UNALIGNED *)(_S)); \ *((USHORT UNALIGNED *)((UCHAR *)(_D)+4)) = *((USHORT UNALIGNED *)((UCHAR *)(_S)+4)); \ } // //UINT //TR_QUERY_FILTER_CLASSES( // IN PTR_FILTER Filter // ) // // This macro returns the currently enabled filter classes. // // NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. // #define TR_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter) // //UINT //TR_QUERY_PACKET_FILTER( // IN PTR_FILTER Filter, // IN NDIS_HANDLE NdisFilterHandle // ) // // This macro returns the currently enabled filter classes for a specific // open instance. // // NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. // #define TR_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \ (((PTR_BINDING_INFO)NdisFilterHandle)->PacketFilters) // //UINT //TR_QUERY_FILTER_ADDRESSES( // IN PTR_FILTER Filter // ) // // This macro returns the currently enabled functional address. // // NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. // #define TR_QUERY_FILTER_ADDRESSES(Filter) ((Filter)->CombinedFunctionalAddress) // //UINT //TR_QUERY_FILTER_GROUP( // IN PTR_FILTER Filter // ) // // This macro returns the currently enabled Group address. // // NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. // #define TR_QUERY_FILTER_Group(Filter) ((Filter)->GroupAddress) #define TR_QUERY_FILTER_GROUP(Filter) ((Filter)->GroupAddress) // //UINT //TR_QUERY_FILTER_BINDING_ADDRESS( // IN PTR_FILTER Filter // IN NDIS_HANDLE NdisFilterHandle, // ) // // This macro returns the currently desired functional addresses // for the specified binding. // // NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. // #define TR_QUERY_FILTER_BINDING_ADDRESS(Filter, NdisFilterHandle) \ (((PTR_BINDING_INFO)NdisFilterHandle)->FunctionalAddress) // //BOOLEAN //TR_QUERY_FILTER_BINDING_GROUP( // IN PTR_FILTER Filter // IN NDIS_HANDLE NdisFilterHandle, // ) // // This macro returns TRUE if the specified binding is using the // current group address. // // NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. // #define TR_QUERY_FILTER_BINDING_GROUP(Filter, NdisFilterHandle) \ (((PTR_BINDING_INFO)NdisFilterHandle)->UsingGroupAddress) // // An action routine type. The routines are called // when a filter type is set for the first time or // no more bindings require a particular type of filter. // // NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. // typedef NDIS_STATUS (*TR_FILTER_CHANGE)( IN UINT OldFilterClasses, IN UINT NewFilterClasses, IN NDIS_HANDLE MacBindingHandle, IN PNDIS_REQUEST NdisRequest, IN BOOLEAN Set ); // // This action routine is called when the functional address // for the card has changed. It is passed the old functional // address as well as the new one. // // NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. // typedef NDIS_STATUS (*TR_ADDRESS_CHANGE)( IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress, IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress, IN NDIS_HANDLE MacBindingHandle, IN PNDIS_REQUEST NdisRequest, IN BOOLEAN Set ); // // This action routine is called when the group address // for the card has changed. It is passed the old group // address as well as the new one. // // NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. // typedef NDIS_STATUS (*TR_GROUP_CHANGE)( IN TR_GROUP_ADDRESS OldGroupAddress, IN TR_GROUP_ADDRESS NewGroupAddress, IN NDIS_HANDLE MacBindingHandle, IN PNDIS_REQUEST NdisRequest, IN BOOLEAN Set ); // // This action routine is called when the mac requests a close for // a particular binding *WHILE THE BINDING IS BEING INDICATED TO // THE PROTOCOL*. The filtering package can't get rid of the open // right away. So this routine will be called as soon as the // NdisIndicateReceive returns. // // NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. // typedef VOID (*TR_DEFERRED_CLOSE)( IN NDIS_HANDLE MacBindingHandle ); // // The binding info is threaded on two lists. When // the binding is free it is on a single freelist. // // When the binding is being used it is on an index list // and possibly on seperate broadcast and directed lists. // typedef struct _TR_BINDING_INFO { NDIS_HANDLE MacBindingHandle; NDIS_HANDLE NdisBindingContext; UINT PacketFilters; TR_FUNCTIONAL_ADDRESS FunctionalAddress; struct _TR_BINDING_INFO *NextOpen; ULONG dummy1; UINT References; UCHAR FilterIndex; BOOLEAN UsingGroupAddress; BOOLEAN ReceivedAPacket; // // the following pointers are used to traverse the specific // filter lists. // TR_FUNCTIONAL_ADDRESS OldFunctionalAddress; UINT OldPacketFilters; BOOLEAN OldUsingGroupAddress; struct _TR_BINDING_INFO *NextDirected; struct _TR_BINDING_INFO *NextBFG; } TR_BINDING_INFO,*PTR_BINDING_INFO; // // An opaque type that contains a filter database. // The MAC need not know how it is structured. // typedef struct _TR_FILTER { // // Spin lock used to protect the filter from multiple accesses. // PNDIS_SPIN_LOCK Lock; // // ORing together of all the FunctionalAddresses. // TR_FUNCTIONAL_ADDRESS CombinedFunctionalAddress; // // Current group address in use. // TR_FUNCTIONAL_ADDRESS GroupAddress; // // Reference count on group address; // UINT GroupReferences; // // Combination of all the filters of all the open bindings. // UINT CombinedPacketFilter; // // Pointer to list of current opens. // PTR_BINDING_INFO OpenList; // // Address of the adapter associated with this filter. // UCHAR AdapterAddress[TR_LENGTH_OF_ADDRESS]; // // Action routines to be invoked on notable changes in the filter. // TR_ADDRESS_CHANGE AddressChangeAction; TR_GROUP_CHANGE GroupChangeAction; TR_FILTER_CHANGE FilterChangeAction; TR_DEFERRED_CLOSE CloseAction; // // Bit mask of opens that are available. // ULONG FreeBindingMask; // // Filter specific list for optimization. // TR_FUNCTIONAL_ADDRESS OldCombinedFunctionalAddress; TR_FUNCTIONAL_ADDRESS OldGroupAddress; UINT OldGroupReferences; UINT OldCombinedPacketFilter; // // The list of bindings are seperated for directed and broadcast/multicast // Promiscuous bindings are on both lists // PTR_BINDING_INFO DirectedList; // List of bindings for directed packets PTR_BINDING_INFO BFGList; // List of bindings for broadcast/functional packets struct _NDIS_MINIPORT_BLOCK *Miniport; } TR_FILTER, *PTR_FILTER; // // Only for internal wrapper use. // VOID TrInitializePackage( VOID ); VOID TrReferencePackage( VOID ); VOID TrDereferencePackage( VOID ); // // Exported functions // EXPORT BOOLEAN TrCreateFilter( IN TR_ADDRESS_CHANGE AddressChangeAction, IN TR_GROUP_CHANGE GroupChangeAction, IN TR_FILTER_CHANGE FilterChangeAction, IN TR_DEFERRED_CLOSE CloseAction, IN PUCHAR AdapterAddress, IN PNDIS_SPIN_LOCK Lock, OUT PTR_FILTER *Filter ); EXPORT VOID TrDeleteFilter( IN PTR_FILTER Filter ); EXPORT BOOLEAN TrNoteFilterOpenAdapter( IN PTR_FILTER Filter, IN NDIS_HANDLE MacBindingHandle, IN NDIS_HANDLE NdisBindingContext, OUT PNDIS_HANDLE NdisFilterHandle ); EXPORT NDIS_STATUS TrDeleteFilterOpenAdapter( IN PTR_FILTER Filter, IN NDIS_HANDLE NdisFilterHandle, IN PNDIS_REQUEST NdisRequest ); EXPORT NDIS_STATUS TrChangeFunctionalAddress( IN PTR_FILTER Filter, IN NDIS_HANDLE NdisFilterHandle, IN PNDIS_REQUEST NdisRequest, IN CHAR FunctionalAddressArray[TR_LENGTH_OF_FUNCTIONAL], IN BOOLEAN Set ); EXPORT NDIS_STATUS TrChangeGroupAddress( IN PTR_FILTER Filter, IN NDIS_HANDLE NdisFilterHandle, IN PNDIS_REQUEST NdisRequest, IN CHAR GroupAddressArray[TR_LENGTH_OF_FUNCTIONAL], IN BOOLEAN Set ); #define TrShouldAddressLoopBackMacro(_Filter, \ _DAddress, \ _SAddress, \ _pfLoopback, \ _pfSelfDirected) \ { \ /* Holds the result of address determinations. */ \ BOOLEAN ResultOfAddressCheck; \ \ BOOLEAN IsSourceRouting; \ \ UINT CombinedFilters; \ \ ULONG GroupAddress; \ \ *(_pfLoopback) = FALSE; \ *(_pfSelfDirected) = FALSE; \ \ do \ { \ /* Convert the 32 bits of the address to a longword. */ \ RetrieveUlong(&GroupAddress, ((_DAddress) + 2)); \ \ /* Check if the destination is a preexisting group address */ \ TR_IS_GROUP((_DAddress), &ResultOfAddressCheck); \ \ if ((ResultOfAddressCheck) && \ (GroupAddress == (_Filter)->GroupAddress) && \ ((_Filter)->GroupReferences != 0)) \ { \ *(_pfLoopback) = TRUE; \ break; \ } \ else \ { \ CombinedFilters = TR_QUERY_FILTER_CLASSES(_Filter); \ \ TR_IS_SOURCE_ROUTING((_SAddress), &IsSourceRouting); \ \ if (IsSourceRouting && (CombinedFilters & NDIS_PACKET_TYPE_SOURCE_ROUTING)) \ { \ *(_pfLoopback) = TRUE; \ break; \ } \ else \ { \ /* First check if it *at least* has the functional address bit. */ \ TR_IS_NOT_DIRECTED((_DAddress), &ResultOfAddressCheck); \ \ if (ResultOfAddressCheck) \ { \ /* It is at least a functional address. Check to see if */ \ /* it is a broadcast address. */ \ \ TR_IS_BROADCAST((_DAddress), &ResultOfAddressCheck); \ \ if (ResultOfAddressCheck) \ { \ if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) \ { \ *(_pfLoopback) = TRUE; \ break; \ } \ } \ else \ { \ if (CombinedFilters & \ (NDIS_PACKET_TYPE_ALL_FUNCTIONAL | NDIS_PACKET_TYPE_FUNCTIONAL)) \ { \ *(_pfLoopback) = TRUE; \ break; \ } \ } \ } \ else \ { \ /* See if it is self-directed. */ \ \ if ((*(ULONG UNALIGNED *)(_DAddress + 2) == \ *(ULONG UNALIGNED *)(&(_Filter)->AdapterAddress[2])) && \ (*(USHORT UNALIGNED *)(_DAddress) == \ *(USHORT UNALIGNED *)(&(_Filter)->AdapterAddress[0]))) \ { \ *(_pfLoopback) = TRUE; \ *(_pfSelfDirected) = FALSE; \ break; \ } \ } \ \ } \ } \ } while (FALSE); \ \ if (CombinedFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) \ { \ *(_pfLoopback) = TRUE; \ } \ } EXPORT BOOLEAN TrShouldAddressLoopBack( IN PTR_FILTER Filter, IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS], IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS] ); EXPORT NDIS_STATUS TrFilterAdjust( IN PTR_FILTER Filter, IN NDIS_HANDLE NdisFilterHandle, IN PNDIS_REQUEST NdisRequest, IN UINT FilterClasses, IN BOOLEAN Set ); EXPORT VOID TrFilterIndicateReceive( IN PTR_FILTER Filter, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ); EXPORT VOID TrFilterDprIndicateReceive( IN PTR_FILTER Filter, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ); EXPORT VOID TrFilterDprIndicateReceivePacket( IN NDIS_HANDLE MiniportHandle, IN PPNDIS_PACKET ReceivedPackets, IN UINT NumberOfPackets ); EXPORT VOID TrFilterIndicateReceiveComplete( IN PTR_FILTER Filter ); EXPORT VOID TrFilterDprIndicateReceiveComplete( IN PTR_FILTER Filter ); #endif // _TR_FILTER_DEFS_