/****************************************************************************
*                                                                           *
* 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) 1993-95  Microsoft Corporation.  All Rights Reserved.       *
*                                                                           *
****************************************************************************/

/*++

Module Name:

    ffilter.h

Abstract:

    Header file for the address filtering library for NDIS MAC's.

Environment:

    Runs in the context of a single MAC driver.

--*/

#ifndef _FDDI_FILTER_DEFS_
#define _FDDI_FILTER_DEFS_

#define FDDI_LENGTH_OF_LONG_ADDRESS 6
#define FDDI_LENGTH_OF_SHORT_ADDRESS 2


//
// ZZZ This is a little-endian specific check.
//
#define FDDI_IS_MULTICAST(Address, AddressLength, Result) \
{ \
    PUCHAR _A = Address; \
    *Result = (BOOLEAN)(_A[0] & ((UCHAR)0x01)); \
}

//
// Check whether the frame is SMT or not.
//
#define FDDI_IS_SMT(FcByte, Result) \
{ \
    *Result = ((FcByte & ((UCHAR)0xf0)) == 0x40); \
}


//
// Check whether an address is broadcast.
//
#define FDDI_IS_BROADCAST(Address, AddressLength, Result) \
{ \
    PUCHAR _A = Address; \
    PUCHAR _E = _A + AddressLength;\
    *Result = TRUE;\
    for (; _A < _E ; _A++) {\
        if (*_A != 0xFF) {\
            *Result = FALSE;\
            break;\
        }\
    }\
}


//
// 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 FDDI_COMPARE_NETWORK_ADDRESSES(A,B,_AddressLength,Result)  \
{                                                                  \
    PUCHAR _A = (PUCHAR)(A);                                       \
    PUCHAR _B = (PUCHAR)(B);                                       \
    if ( *(USHORT UNALIGNED *)_A >                                 \
         *(USHORT UNALIGNED *)_B ) {                               \
        *Result = 1;                                               \
    } else if ( *(USHORT UNALIGNED *)_A <                          \
                *(USHORT UNALIGNED *)_B ) {                        \
        *Result = (UINT)-1;                                        \
    } else if (_AddressLength == 2) {                              \
        *Result = 0;                                               \
    } else 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 {                                                       \
        *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 FDDI_COMPARE_NETWORK_ADDRESSES_EQ(A,B,_AddressLength,Result)    \
{                                                                       \
    PUCHAR _A = (PUCHAR)(A);                                            \
    PUCHAR _B = (PUCHAR)(B);                                            \
    if ( ( *(USHORT UNALIGNED *)_A ==                                   \
           *(USHORT UNALIGNED *)_B ) &&                                 \
         ( ( (_AddressLength) == 2 ) ||                                 \
           ( *(ULONG UNALIGNED *)&_A[2] ==                              \
             *(ULONG UNALIGNED *)&_B[2] ) ) ) {                         \
        *Result = 0;                                                    \
    } else {                                                            \
        *Result = 1;                                                    \
    }                                                                   \
}


//
// This macro is used to copy from one network address to
// another.
//
#define FDDI_COPY_NETWORK_ADDRESS(D,S,AddressLength) \
{ \
    PCHAR _D = (D); \
    PCHAR _S = (S); \
    UINT _C = (AddressLength);\
    for ( ; _C > 0 ; _D++, _S++, _C--) {\
        *_D = *_S;\
    }\
}


//
//UINT
//FDDI_QUERY_FILTER_CLASSES(
//    IN PFDDI_FILTER Filter
//    )
//
// This macro returns the currently enabled filter classes.
//
// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
//
#define FDDI_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)


//
//UINT
//FDDI_QUERY_PACKET_FILTER(
//    IN PFDDI_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 FDDI_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
       (((PFDDI_BINDING_INFO)(NdisFilterHandle))->PacketFilters)


//
//UINT
//FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(
//    IN PFDDI_FILTER Filter
//    )
//
// This macro returns the number of multicast addresses in the
// multicast address list.
//
// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
//
#define FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(Filter) ((Filter)->NumberOfLongAddresses)


//
//UINT
//FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(
//    IN PFDDI_FILTER Filter
//    )
//
// This macro returns the number of multicast addresses in the
// multicast address list.
//
// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
//
#define FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(Filter) ((Filter)->NumberOfShortAddresses)


//
// 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
(*FDDI_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 a new multicast address
// list is given to the filter. The action routine is given
// arrays containing the old and new multicast addresses.
//
// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
//
typedef
NDIS_STATUS
(*FDDI_ADDRESS_CHANGE)(
    IN UINT OldLongAddressCount,
    IN CHAR OldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
    IN UINT NewLongAddressCount,
    IN CHAR NewLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
    IN UINT OldShortAddressCount,
    IN CHAR OldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
    IN UINT NewShortAddressCount,
    IN CHAR NewShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
    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
(*FDDI_DEFERRED_CLOSE)(
    IN NDIS_HANDLE MacBindingHandle
    );

typedef ULONG FDDI_MASK,*PFDDI_MASK;

//
// Maximum number of opens the filter package will support.  This is
// the max so that bit masks can be used instead of a spaghetti of
// pointers.
//
#define FDDI_FILTER_MAX_OPENS (sizeof(ULONG) * 8)

//
// 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 a doubly linked
// index list.
//
typedef struct _FDDI_BINDING_INFO {
    NDIS_HANDLE MacBindingHandle;
    NDIS_HANDLE NdisBindingContext;
    UINT PacketFilters;
    ULONG References;
    struct _FDDI_BINDING_INFO *NextOpen;
    struct _FDDI_BINDING_INFO *PrevOpen;
    BOOLEAN ReceivedAPacket;
    UCHAR FilterIndex;
} FDDI_BINDING_INFO,*PFDDI_BINDING_INFO;

//
// An opaque type that contains a filter database.
// The MAC need not know how it is structured.
//
typedef struct _FDDI_FILTER {

    //
    // Spin lock used to protect the filter from multiple accesses.
    //
    PNDIS_SPIN_LOCK Lock;

    //
    // Pointer to an array of 6 character arrays holding the
    // multicast addresses requested for filtering.
    //
    CHAR (*MulticastLongAddresses)[FDDI_LENGTH_OF_LONG_ADDRESS];

    //
    // Pointer to an array of FDDI_MASKS that work in conjuction with
    // the MulticastLongAddress array.  In the masks, a bit being enabled
    // indicates that the binding with the given FilterIndex is using
    // the corresponding address.
    //
    FDDI_MASK *BindingsUsingLongAddress;

    //
    // Pointer to an array of 2 character arrays holding the
    // multicast addresses requested for filtering.
    //
    CHAR (*MulticastShortAddresses)[FDDI_LENGTH_OF_SHORT_ADDRESS];

    //
    // Pointer to an array of FDDI_MASKS that work in conjuction with
    // the MulticastShortAddress array.  In the masks, a bit being enabled
    // indicates that the binding with the given FilterIndex is using
    // the corresponding address.
    //
    FDDI_MASK *BindingsUsingShortAddress;

    //
    // Combination of all the filters of all the open bindings.
    //
    UINT CombinedPacketFilter;

    //
    // Pointer for traversing the open list.
    //
    PFDDI_BINDING_INFO OpenList;


    //
    // Action routines to be invoked on notable changes in the filter.
    //

    FDDI_ADDRESS_CHANGE AddressChangeAction;
    FDDI_FILTER_CHANGE FilterChangeAction;
    FDDI_DEFERRED_CLOSE CloseAction;

    //
    // The maximum number of long addresses used for filtering.
    //
    UINT MaximumMulticastLongAddresses;

    //
    // The maximum number of short addresses used for filtering.
    //
    UINT MaximumMulticastShortAddresses;

    //
    // The current number of addresses in the LongAddress filter.
    //
    UINT NumberOfLongAddresses;

    //
    // The current number of addresses in the ShortAddress filter.
    //
    UINT NumberOfShortAddresses;

    //
    // Bit mask of opens that are available.
    //
    ULONG FreeBindingMask;

    //
    // Long Address of the adapter.
    //
    UCHAR AdapterLongAddress[FDDI_LENGTH_OF_LONG_ADDRESS];

    //
    // Short Address of the adapter.
    //
    UCHAR AdapterShortAddress[FDDI_LENGTH_OF_SHORT_ADDRESS];

} FDDI_FILTER,*PFDDI_FILTER;

EXPORT
BOOLEAN
FddiCreateFilter(
    IN UINT MaximumMulticastLongAddresses,
    IN UINT MaximumMulticastShortAddresses,
    IN FDDI_ADDRESS_CHANGE AddressChangeAction,
    IN FDDI_FILTER_CHANGE FilterChangeAction,
    IN FDDI_DEFERRED_CLOSE CloseAction,
    IN PUCHAR AdapterLongAddress,
    IN PUCHAR AdapterShortAddress,
    IN PNDIS_SPIN_LOCK Lock,
    OUT PFDDI_FILTER *Filter
    );

EXPORT
VOID
FddiDeleteFilter(
    IN PFDDI_FILTER Filter
    );

EXPORT
BOOLEAN
FddiNoteFilterOpenAdapter(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE MacBindingHandle,
    IN NDIS_HANDLE NdisBindingContext,
    OUT PNDIS_HANDLE NdisFilterHandle
    );

EXPORT
NDIS_STATUS
FddiDeleteFilterOpenAdapter(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE NdisFilterHandle,
    IN PNDIS_REQUEST NdisRequest
    );

EXPORT
NDIS_STATUS
FddiChangeFilterLongAddresses(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE NdisFilterHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN UINT AddressCount,
    IN CHAR Addresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
    IN BOOLEAN Set
    );

EXPORT
NDIS_STATUS
FddiChangeFilterShortAddresses(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE NdisFilterHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN UINT AddressCount,
    IN CHAR Addresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
    IN BOOLEAN Set
    );

EXPORT
BOOLEAN
FddiShouldAddressLoopBack(
    IN PFDDI_FILTER Filter,
    IN CHAR Address[],
    IN UINT LengthOfAddress
    );

EXPORT
NDIS_STATUS
FddiFilterAdjust(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE NdisFilterHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN UINT FilterClasses,
    IN BOOLEAN Set
    );

EXPORT
UINT
FddiNumberOfOpenFilterLongAddresses(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE NdisFilterHandle
    );

EXPORT
UINT
FddiNumberOfOpenFilterShortAddresses(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE NdisFilterHandle
    );

EXPORT
VOID
FddiQueryGlobalFilterLongAddresses(
    OUT PNDIS_STATUS Status,
    IN PFDDI_FILTER Filter,
    IN UINT SizeOfArray,
    OUT PUINT NumberOfAddresses,
    IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
    );

EXPORT
VOID
FddiQueryGlobalFilterShortAddresses(
    OUT PNDIS_STATUS Status,
    IN PFDDI_FILTER Filter,
    IN UINT SizeOfArray,
    OUT PUINT NumberOfAddresses,
    IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
    );

EXPORT
VOID
FddiQueryOpenFilterLongAddresses(
    OUT PNDIS_STATUS Status,
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE NdisFilterHandle,
    IN UINT SizeOfArray,
    OUT PUINT NumberOfAddresses,
    IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
    );

EXPORT
VOID
FddiQueryOpenFilterShortAddresses(
    OUT PNDIS_STATUS Status,
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE NdisFilterHandle,
    IN UINT SizeOfArray,
    OUT PUINT NumberOfAddresses,
    IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
    );

EXPORT
VOID
FddiFilterIndicateReceive(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE MacReceiveContext,
    IN PCHAR Address,
    IN UINT AddressLength,
    IN PVOID HeaderBuffer,
    IN UINT HeaderBufferSize,
    IN PVOID LookaheadBuffer,
    IN UINT LookaheadBufferSize,
    IN UINT PacketSize
    );

EXPORT
VOID
FddiFilterDprIndicateReceive(
    IN PFDDI_FILTER Filter,
    IN NDIS_HANDLE MacReceiveContext,
    IN PCHAR Address,
    IN UINT AddressLength,
    IN PVOID HeaderBuffer,
    IN UINT HeaderBufferSize,
    IN PVOID LookaheadBuffer,
    IN UINT LookaheadBufferSize,
    IN UINT PacketSize
    );

EXPORT
VOID
FddiFilterIndicateReceiveComplete(
    IN PFDDI_FILTER Filter
    );

EXPORT
VOID
FddiFilterDprIndicateReceiveComplete(
    IN PFDDI_FILTER Filter
    );

#endif // _FDDI_FILTER_DEFS_
