diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/ndis40/tfilter.c | 2813 |
1 files changed, 2813 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndis40/tfilter.c b/private/ntos/ndis/ndis40/tfilter.c new file mode 100644 index 000000000..bb0754b3a --- /dev/null +++ b/private/ntos/ndis/ndis40/tfilter.c @@ -0,0 +1,2813 @@ +/*++ + +Copyright (c) 1990-1995 Microsoft Corporation + +Module Name: + + tfilter.c + +Abstract: + + This module implements a set of library routines to handle packet + filtering for NDIS MAC drivers. + +Author: + + Anthony V. Ercolano (Tonye) 03-Aug-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent on OS/2 and DOS. + +Revision History: + + Adam Barr (adamba) 19-Mar-1991 + + - Modified for Token-Ring + Jameel Hyder (JameelH) Re-organization 01-Jun-95 + +--*/ + +#include <precomp.h> +#pragma hdrstop + +// +// Define the module number for debug code. +// +#define MODULE_NUMBER MODULE_TFILTER + +// +// Used in case we have to call TrChangeFunctionalAddress or +// TrChangeGroupAddress with a NULL address. +// +static CHAR NullFunctionalAddress[4] = { 0x00 }; + + +// +// Maximum number of supported opens +// +#define TR_FILTER_MAX_OPENS 32 + + +// +// VOID +// TR_FILTER_ALLOC_OPEN( +// IN PTR_FILTER Filter, +// OUT PUINT FilterIndex +// ) +// +///*++ +// +//Routine Description: +// +// Allocates an open block. This only allocate the index, not memory for +// the open block. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - pointer to place to store the index. +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define TR_FILTER_ALLOC_OPEN(Filter, FilterIndex) \ +{ \ + UINT i; \ + for (i = 0; i < TR_FILTER_MAX_OPENS; i++) \ + { \ + if (IS_BIT_SET_IN_MASK(i, (Filter)->FreeBindingMask)) \ + { \ + *(FilterIndex) = i; \ + CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \ + break; \ + } \ + } \ +} + +// +// VOID +// TR_FILTER_FREE_OPEN( +// IN PTR_FILTER Filter, +// IN PTR_BINDING_INFO LocalOpen +// ) +// +///*++ +// +//Routine Description: +// +// Frees an open block. Also frees the memory associated with the open. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - Index to free +// +//Return Value: +// +// None +// +//--*/ +#define TR_FILTER_FREE_OPEN(Filter, LocalOpen)\ +{\ + SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \ + FreePhys((LocalOpen), sizeof(TR_BINDING_INFO));\ +} + +#define TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(_F) \ +IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \ +{ \ + if (!((_F)->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) \ + { \ + /* \ + We should never receive broadcast packets \ + to someone else unless in p-mode. \ + */ \ + DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \ + ("Bad driver, indicating broadcast packets when not set to.\n"));\ + DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \ + } \ +} + + +#define TR_CHECK_FOR_INVALID_DIRECTED_INDICATION(_F, _A) \ +IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \ +{ \ + /* \ + The result of comparing an element of the address \ + array and the functional address. \ + \ + Result < 0 Implies the adapter address is greater. \ + Result > 0 Implies the address is greater. \ + Result = 0 Implies that the they are equal. \ + */ \ + INT Result; \ + \ + TR_COMPARE_NETWORK_ADDRESSES_EQ( \ + (_F)->AdapterAddress, \ + (_A), \ + &Result); \ + if (Result != 0) \ + { \ + /* \ + We should never receive directed packets \ + to someone else unless in p-mode. \ + */ \ + DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \ + ("Bad driver, indicating packets to another station when not in promiscuous mode.\n"));\ + DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \ + } \ +} + + +VOID +trRemoveBindingFromLists( + IN PTR_FILTER Filter, + IN PTR_BINDING_INFO Binding + ) +/*++ + + This routine will remove a binding from all of the list in a + filter database. These lists include the list of bindings, + the directed filter list and the broadcast filter list. + +Arguments: + + Filter - Pointer to the filter database to remove the binding from. + Binding - Pointer to the binding to remove. + +--*/ +{ + PTR_BINDING_INFO *ppBI; + + // + // Remove the binding from the filters list + // of all bindings. + // + for (ppBI = &Filter->OpenList; + *ppBI != NULL; + ppBI = &(*ppBI)->NextOpen) + { + if (*ppBI == Binding) + { + *ppBI = Binding->NextOpen; + break; + } + } + ASSERT(*ppBI == Binding->NextOpen); + + // + // Remove it from the directed binding list - conditionally + // + for (ppBI = &Filter->DirectedList; + *ppBI != NULL; + ppBI = &(*ppBI)->NextDirected) + { + if (*ppBI == Binding) + { + *ppBI = Binding->NextDirected; + break; + } + } + + // + // Remove it from the broadcast/functional/group binding list - conditionally + // + for (ppBI = &Filter->BFGList; + *ppBI != NULL; + ppBI = &(*ppBI)->NextBFG) + { + if (*ppBI == Binding) + { + *ppBI = Binding->NextBFG; + break; + } + } + + Binding->NextDirected = NULL; + Binding->NextBFG = NULL; + Binding->NextOpen = NULL; +} + +VOID +trRemoveAndFreeBinding( + IN PTR_FILTER Filter, + IN PTR_BINDING_INFO Binding, + IN BOOLEAN fCallCloseAction + ) +/*++ + +Routine Description: + + This routine will remove a binding from the filter database and + indicate a receive complete if necessary. This was made a function + to remove code redundancey in following routines. Its not time + critical so it's cool. + +Arguments: + + Filter - Pointer to the filter database to remove the binding from. + Binding - Pointer to the binding to remove. + fCallCloseAction - TRUE if we should call the filter's close + action routine. FALSE if not. + +--*/ +{ + // + // Remove the binding. + // + trRemoveBindingFromLists(Filter, Binding); + + // + // If we have received and packet indications then + // notify the binding of the indication completion. + // + if (Binding->ReceivedAPacket) + { + if (NULL != Filter->Miniport) + { + NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport); + } + else + { + NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock); + } + + FilterIndicateReceiveComplete(Binding->NdisBindingContext); + + if (NULL != Filter->Miniport) + { + NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport); + } + else + { + NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + } + } + + // + // Do we need to call the close action? + // + if (fCallCloseAction) + { + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + Filter->CloseAction(Binding->MacBindingHandle); + } + + // + // Free the open. + // + TR_FILTER_FREE_OPEN(Filter, Binding); +} + + + +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 + ) + +/*++ + +Routine Description: + + This routine is used to create and initialize the filter database. + +Arguments: + + AddressChangeAction - Action routine to call when the ORing together + of the functional address desired by all the bindings had changed. + + GroupChangeAction - Action routine to call when the group address + desired by all the bindings had changed. + + FilterChangeAction - Action routine to call when a binding sets or clears + a particular filter class and it is the first or only binding using + the filter class. + + CloseAction - This routine is called if a binding closes while + it is being indicated to via NdisIndicateReceive. It will be + called upon return from NdisIndicateReceive. + + AdapterAddress - the address of the adapter associated with this filter + database. + + Lock - Pointer to the lock that should be held when mutual exclusion + is required. + + Filter - A pointer to a TR_FILTER. This is what is allocated and + created by this routine. + +Return Value: + + If the function returns false then one of the parameters exceeded + what the filter was willing to support. + +--*/ + +{ + PTR_FILTER LocalFilter; + NDIS_STATUS AllocStatus; + + + // + // Allocate the database and it's associated arrays. + // + + AllocStatus = AllocPhys(&LocalFilter, sizeof(TR_FILTER)); + *Filter = LocalFilter; + + if (AllocStatus != NDIS_STATUS_SUCCESS) + return(FALSE); + + TrReferencePackage(); + + ZeroMemory(LocalFilter, sizeof(TR_FILTER)); + + LocalFilter->FreeBindingMask = (ULONG)-1; + + LocalFilter->Lock = Lock; + + TR_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress); + LocalFilter->AddressChangeAction = AddressChangeAction; + LocalFilter->GroupChangeAction = GroupChangeAction; + LocalFilter->FilterChangeAction = FilterChangeAction; + LocalFilter->CloseAction = CloseAction; + + return(TRUE); +} + +// +// NOTE : THIS ROUTINE CANNOT BE PAGEABLE +// + +VOID +TrDeleteFilter( + IN PTR_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is used to delete the memory associated with a filter + database. Note that this routines *ASSUMES* that the database + has been cleared of any active filters. + +Arguments: + + Filter - A pointer to a TR_FILTER to be deleted. + +Return Value: + + None. + +--*/ + +{ + ASSERT(Filter->OpenList == NULL); + + FreePhys(Filter, sizeof(TR_FILTER)); + + TrDereferencePackage(); +} + + +BOOLEAN +TrNoteFilterOpenAdapter( + IN PTR_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ) + +/*++ + +Routine Description: + + This routine is used to add a new binding to the filter database. + + NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN + IT IS CALLED. + +Arguments: + + Filter - A pointer to the previously created and initialized filter + database. + + MacBindingHandle - The MAC supplied value to the protocol in response + to a call to MacOpenAdapter. + + NdisBindingContext - An NDIS supplied value to the call to MacOpenAdapter. + + NdisFilterHandle - A pointer to the open block. + +Return Value: + + Will return false if creating a new filter index will cause the maximum + number of filter indexes to be exceeded. + +--*/ + +{ + NDIS_STATUS AllocStatus; + + // + // Will hold the value of the filter index so that we + // need not indirectly address through pointer parameter. + // + UINT LocalIndex; + + // + // This new open + // + PTR_BINDING_INFO LocalOpen; + + PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext; + + if (Filter->FreeBindingMask == 0) + return(FALSE); + + AllocStatus = AllocPhys(&LocalOpen, sizeof(TR_BINDING_INFO)); + if (AllocStatus != NDIS_STATUS_SUCCESS) + return(FALSE); + + // + // Zero the memory + // + ZeroMemory(LocalOpen, sizeof(TR_BINDING_INFO)); + + // + // Get place for the open and insert it. + // + TR_FILTER_ALLOC_OPEN(Filter, &LocalIndex); + + LocalOpen->NextOpen = Filter->OpenList; + Filter->OpenList = LocalOpen; + + LocalOpen->References = 1; + LocalOpen->FilterIndex = (UCHAR)LocalIndex; + LocalOpen->MacBindingHandle = MacBindingHandle; + LocalOpen->NdisBindingContext = NdisBindingContext; + + *NdisFilterHandle = (PTR_BINDING_INFO)LocalOpen; + + return(TRUE); +} + + +NDIS_STATUS +TrDeleteFilterOpenAdapter( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + When an adapter is being closed this routine should + be called to delete knowledge of the adapter from + the filter database. This routine is likely to call + action routines associated with clearing filter classes + and addresses. + + NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION + ROUTINES FOR DELETING THE FILTER CLASSES OR THE FUNCTIONAL ADDRESSES + HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING + OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF + SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT + TO CODE A CLOSE ROUTINE! + + NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routines, + this will be passed to it. + +Return Value: + + If action routines are called by the various address and filtering + routines the this routine will likely return the status returned + by those routines. The exception to this rule is noted below. + + Given that the filter and address deletion routines return a status + NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then + try to return the filter index to the freelist. If the routine + detects that this binding is currently being indicated to via + NdisIndicateReceive, this routine will return a status of + NDIS_STATUS_CLOSING_INDICATING. + +--*/ + +{ + // + // Holds the status returned from the packet filter and address + // deletion routines. Will be used to return the status to + // the caller of this routine. + // + NDIS_STATUS StatusToReturn; + + PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle; + + // + // Set the packet filter to NONE. + // + StatusToReturn = TrFilterAdjust(Filter, + NdisFilterHandle, + NdisRequest, + (UINT)0, + FALSE); + if ((NDIS_STATUS_SUCCESS == StatusToReturn) || + (NDIS_STATUS_PENDING == StatusToReturn)) + { + NDIS_STATUS StatusToReturn2; + + // + // Clear the functional address. + // + StatusToReturn2 = TrChangeFunctionalAddress( + Filter, + NdisFilterHandle, + NdisRequest, + NullFunctionalAddress, + FALSE); + if (StatusToReturn2 != NDIS_STATUS_SUCCESS) + { + StatusToReturn = StatusToReturn2; + } + } + + if (((StatusToReturn == NDIS_STATUS_SUCCESS) || + (StatusToReturn == NDIS_STATUS_PENDING)) && + (LocalOpen->UsingGroupAddress)) + { + Filter->GroupReferences--; + + LocalOpen->UsingGroupAddress = FALSE; + + if (Filter->GroupReferences == 0) + { + NDIS_STATUS StatusToReturn2; + + // + // Clear the group address if no other bindings are using it. + // + StatusToReturn2 = TrChangeGroupAddress( + Filter, + NdisFilterHandle, + NdisRequest, + NullFunctionalAddress, + FALSE); + if (StatusToReturn2 != NDIS_STATUS_SUCCESS) + { + StatusToReturn = StatusToReturn2; + } + } + } + + if ((StatusToReturn == NDIS_STATUS_SUCCESS) || + (StatusToReturn == NDIS_STATUS_PENDING)) + { + // + // If this is the last reference to the open - remove it. + // + if ((--(LocalOpen->References)) == 0) + { + // + // Remove the binding and indicate a receive complete + // if necessary. + // + trRemoveAndFreeBinding(Filter, LocalOpen, FALSE); + } + else + { + // + // Let the caller know that this "reference" to the open + // is still "active". The close action routine will be + // called upon return from NdisIndicateReceive. + // + StatusToReturn = NDIS_STATUS_CLOSING_INDICATING; + } + } + + return(StatusToReturn); +} + +VOID +trUndoChangeFunctionalAddress( + IN PTR_FILTER Filter, + IN PTR_BINDING_INFO Binding +) +{ + // + // The user returned a bad status. Put things back as + // they were. + // + Binding->FunctionalAddress = Binding->OldFunctionalAddress; + Filter->CombinedFunctionalAddress = Filter->OldCombinedFunctionalAddress; +} + + + +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 + ) + +/*++ + +Routine Description: + + The ChangeFunctionalAddress routine will call an action + routine when the overall functional address for the adapter + has changed. + + If the action routine returns a value other than pending or + success then this routine has no effect on the functional address + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + FunctionalAddress - The new functional address for this binding. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Holds the functional address as a longword. + // + TR_FUNCTIONAL_ADDRESS FunctionalAddress; + + // + // Pointer to the open. + // + PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust; + + // + // Simple iteration variable. + // + PTR_BINDING_INFO OpenList; + + + // + // Convert the 32 bits of the address to a longword. + // + RetrieveUlong(&FunctionalAddress, FunctionalAddressArray); + + // + // Set the new filter information for the open. + // + LocalOpen->OldFunctionalAddress = LocalOpen->FunctionalAddress; + LocalOpen->FunctionalAddress = FunctionalAddress; + + // + // Contains the value of the combined functional address before + // it is adjusted. + // + Filter->OldCombinedFunctionalAddress = Filter->CombinedFunctionalAddress; + + // + // We always have to reform the compbined filter since + // this filter index may have been the only filter index + // to use a particular bit. + // + + for (OpenList = Filter->OpenList, Filter->CombinedFunctionalAddress = 0; + OpenList != NULL; + OpenList = OpenList->NextOpen) + { + Filter->CombinedFunctionalAddress |= OpenList->FunctionalAddress; + } + + if (Filter->OldCombinedFunctionalAddress != Filter->CombinedFunctionalAddress) + { + StatusOfAdjust = Filter->AddressChangeAction( + Filter->OldCombinedFunctionalAddress, + Filter->CombinedFunctionalAddress, + LocalOpen->MacBindingHandle, + NdisRequest, + Set); + + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) + { + // + // The user returned a bad status. Put things back as + // they were. + // + trUndoChangeFunctionalAddress(Filter, LocalOpen); + } + } + else + { + StatusOfAdjust = NDIS_STATUS_SUCCESS; + } + + return(StatusOfAdjust); +} + +VOID +trUndoChangeGroupAddress( + IN PTR_FILTER Filter, + IN PTR_BINDING_INFO Binding + ) +{ + // + // The user returned a bad status. Put things back as + // they were. + // + Filter->GroupAddress = Filter->OldGroupAddress; + Filter->GroupReferences = Filter->OldGroupReferences; + + Binding->UsingGroupAddress = Binding->OldUsingGroupAddress; +} + + +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 + ) + +/*++ + +Routine Description: + + The ChangeGroupAddress routine will call an action + routine when the overall group address for the adapter + has changed. + + If the action routine returns a value other than pending or + success then this routine has no effect on the group address + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + GroupAddressArray - The new group address for this binding. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Holds the Group address as a longword. + // + TR_FUNCTIONAL_ADDRESS GroupAddress; + + PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust = NDIS_STATUS_PENDING; + + // + // Convert the 32 bits of the address to a longword. + // + RetrieveUlong(&GroupAddress, GroupAddressArray); + + Filter->OldGroupAddress = Filter->GroupAddress; + Filter->OldGroupReferences = Filter->GroupReferences; + LocalOpen->OldUsingGroupAddress = LocalOpen->UsingGroupAddress; + + // + // If the new group address is 0 then a binding is + // attempting to delete the current group address. + // + if (0 == GroupAddress) + { + // + // Is the binding using the group address? + // + if (LocalOpen->UsingGroupAddress) + { + // + // Remove the bindings reference. + // + Filter->GroupReferences--; + LocalOpen->UsingGroupAddress = FALSE; + + // + // Are any other bindings using the group address? + // + if (Filter->GroupReferences != 0) + { + // + // Since other bindings are using the group address + // we cannot tell the driver to remove it. + // + return(NDIS_STATUS_SUCCESS); + } + + // + // We are the only binding using the group address + // so we fall through and call the driver to delete it. + // + } + else + { + // + // This binding is not using the group address but + // it is trying to clear it. + // + if (Filter->GroupReferences != 0) + { + // + // There are other bindings using the group address + // so we cannot delete it. + // + return(NDIS_STATUS_GROUP_ADDRESS_IN_USE); + } + else + { + // + // There are no bindings using the group address. + // + return(NDIS_STATUS_SUCCESS); + } + } + } + else + { + // + // See if this address is already the current address. + // + if (GroupAddress == Filter->GroupAddress) + { + // + // If the current binding is already using the + // group address then do nothing. + // + if (LocalOpen->UsingGroupAddress) + { + return(NDIS_STATUS_SUCCESS); + } + + // + // If there are already bindings that are using the group + // address then we just need to update the bindings + // information. + // + if (Filter->GroupReferences != 0) + { + // + // We can take care of everything here... + // + Filter->GroupReferences++; + LocalOpen->UsingGroupAddress = TRUE; + + return(NDIS_STATUS_SUCCESS); + } + } + else + { + // + // If there are other bindings using the address then + // we can't change it. + // + if (Filter->GroupReferences > 1) + { + return(NDIS_STATUS_GROUP_ADDRESS_IN_USE); + } + + // + // Is there only one binding using the address? + // If is it some other binding? + // + if ((Filter->GroupReferences == 1) && + (!LocalOpen->UsingGroupAddress)) + { + // + // Some other binding is using the group address. + // + return(NDIS_STATUS_GROUP_ADDRESS_IN_USE); + } + + // + // Is this the only binding using the address. + // + if ((Filter->GroupReferences == 1) && + (LocalOpen->UsingGroupAddress)) + { + // + // Remove the reference. + // + Filter->GroupReferences = 0; + LocalOpen->UsingGroupAddress = FALSE; + } + } + } + + // + // Set the new filter information for the open. + // + Filter->GroupAddress = GroupAddress; + StatusOfAdjust = Filter->GroupChangeAction( + Filter->OldGroupAddress, + Filter->GroupAddress, + LocalOpen->MacBindingHandle, + NdisRequest, + Set); + + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) + { + // + // The user returned a bad status. Put things back as + // they were. + // + trUndoChangeGroupAddress(Filter, LocalOpen); + } + else if (GroupAddress == 0) + { + LocalOpen->UsingGroupAddress = FALSE; + Filter->GroupReferences = 0; + } + else + { + LocalOpen->UsingGroupAddress = TRUE; + Filter->GroupReferences = 1; + } + + return(StatusOfAdjust); +} + + +VOID +trUpdateDirectedBindingList( + IN OUT PTR_FILTER Filter, + IN PTR_BINDING_INFO Binding, + IN BOOLEAN fAddBindingToList + ) +{ + PTR_BINDING_INFO CurrentBinding; + BOOLEAN AlreadyOnList; + + // + // Do we need to add it to the directed list? + // + if (fAddBindingToList) + { + // + // First we need to see if it is already on the + // directed list. + // + for (CurrentBinding = Filter->DirectedList, AlreadyOnList = FALSE; + CurrentBinding != NULL; + CurrentBinding = CurrentBinding->NextDirected + ) + { + if (CurrentBinding == Binding) + { + AlreadyOnList = TRUE; + } + } + + if (!AlreadyOnList) + { + Binding->NextDirected = Filter->DirectedList; + Filter->DirectedList = Binding; + } + } + else + { + PTR_BINDING_INFO *ppBI; + + for (ppBI = &Filter->DirectedList; + *ppBI != NULL; + ppBI = &(*ppBI)->NextDirected) + { + if (*ppBI == Binding) + { + *ppBI = Binding->NextDirected; + break; + } + } + Binding->NextDirected = NULL; + } +} + + +VOID +trUpdateBroadcastBindingList( + IN OUT PTR_FILTER Filter, + IN PTR_BINDING_INFO Binding, + IN BOOLEAN fAddToList + ) +{ + PTR_BINDING_INFO CurrentBinding; + BOOLEAN AlreadyOnList; + + // + // Do we need to add it to the directed list? + // + if (fAddToList) + { + // + // First we need to see if it is already on the + // directed list. + // + for (CurrentBinding = Filter->BFGList, AlreadyOnList = FALSE; + CurrentBinding != NULL; + CurrentBinding = CurrentBinding->NextBFG) + { + if (CurrentBinding == Binding) + { + AlreadyOnList = TRUE; + } + } + + if (!AlreadyOnList) + { + Binding->NextBFG = Filter->BFGList; + Filter->BFGList = Binding; + } + } + else + { + PTR_BINDING_INFO *ppBI; + + for (ppBI = &Filter->BFGList; + *ppBI != NULL; + ppBI = &(*ppBI)->NextBFG) + { + if (*ppBI == Binding) + { + *ppBI = Binding->NextBFG; + break; + } + } + + Binding->NextBFG = NULL; + } +} + + +VOID +trUpdateSpecificBindingLists( + IN OUT PTR_FILTER Filter, + IN PTR_BINDING_INFO Binding +) +{ + BOOLEAN fOnDirectedList = FALSE; + BOOLEAN fOnBFGList = FALSE; + BOOLEAN fAddToDirectedList = FALSE; + BOOLEAN fAddToBFGList = FALSE; + + // + // If the old filter is promsicuous then it is currently on + // both lists. + // + if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) + { + fOnDirectedList = TRUE; + fOnBFGList = TRUE; + } + else + { + // + // If the binding had the directed bit set then it is on + // the directed list. + // + if (Binding->OldPacketFilters & NDIS_PACKET_TYPE_DIRECTED) + { + fOnDirectedList = TRUE; + } + + // + // If the binding had the broadcast/functional/group bit set then it is on + // the broadcast/functional list. + // + if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_GROUP | + NDIS_PACKET_TYPE_FUNCTIONAL| + NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) + { + fOnBFGList = TRUE; + } + } + + // + // If the current filter has the promsicuous bit set then we + // need to add it to both lists. + // + if (Binding->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) + { + fAddToDirectedList = TRUE; + fAddToBFGList = TRUE; + } + else + { + // + // Was the directed bit set? + // + if (Binding->PacketFilters & NDIS_PACKET_TYPE_DIRECTED) + { + fAddToDirectedList = TRUE; + } + + // + // Was the broadcast bit set? + // + if (Binding->PacketFilters & (NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_GROUP | + NDIS_PACKET_TYPE_FUNCTIONAL | + NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) + { + fAddToBFGList = TRUE; + } + } + + // + // Determine if the binding should be added or removed from + // the directed list. + // + if (!fOnDirectedList && fAddToDirectedList) + { + // + // Add the binding to the directed list. + // + trUpdateDirectedBindingList(Filter, Binding, TRUE); + } + else if (fOnDirectedList && !fAddToDirectedList) + { + // + // Remove it from the directed list. + // + trUpdateDirectedBindingList(Filter, Binding, FALSE); + } + + // + // Determine if the binding should be added or removed from + // the broadcast list. + // + if (!fOnBFGList && fAddToBFGList) + { + // + // Add the binding to the broadcast list. + // + trUpdateBroadcastBindingList(Filter, Binding, TRUE); + } + else if (fOnBFGList && !fAddToBFGList) + { + // + // Remove the binding from the broadcast list. + // + trUpdateBroadcastBindingList(Filter, Binding, FALSE); + } + +} + +VOID +trUndoFilterAdjust( + IN PTR_FILTER Filter, + IN PTR_BINDING_INFO Binding +) +{ + // + // The user returned a bad status. Put things back as + // they were. + // + Binding->PacketFilters = Binding->OldPacketFilters; + Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter; + + // + // Remove the binding from the filter lists. + // + trUpdateSpecificBindingLists(Filter, Binding); +} + + +NDIS_STATUS +TrFilterAdjust( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The FilterAdjust routine will call an action routine when a + particular filter class is changes from not being used by any + binding to being used by at least one binding or vice versa. + + If the action routine returns a value other than pending or + success then this routine has no effect on the packet filters + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + FilterClasses - The filter classes that are to be added or + deleted. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Pointer to the open + // + PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust; + + // + // Simple iteration variable. + // + PTR_BINDING_INFO OpenList; + + // + // Set the new filter information for the open. + // + LocalOpen->OldPacketFilters = LocalOpen->PacketFilters; + LocalOpen->PacketFilters = FilterClasses; + Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter; + + // + // We always have to reform the compbined filter since + // this filter index may have been the only filter index + // to use a particular bit. + // + for (OpenList = Filter->OpenList, Filter->CombinedPacketFilter = 0; + OpenList != NULL; + OpenList = OpenList->NextOpen) + { + Filter->CombinedPacketFilter |= OpenList->PacketFilters; + } + + // + // Update the specific binding lists with the new information. + // + trUpdateSpecificBindingLists(Filter, LocalOpen); + + // + // If the packet filter has changed then we need to call down to + // the change action handler. + // + if ((Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL) != + (Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL)) + { + StatusOfAdjust = Filter->FilterChangeAction( + Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL, + Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL, + LocalOpen->MacBindingHandle, + NdisRequest, + Set); + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) + { + // + // The user returned a bad status. Put things back as + // they were. + // + trUndoFilterAdjust(Filter, LocalOpen); + } + } + else + { + StatusOfAdjust = NDIS_STATUS_SUCCESS; + } + + return(StatusOfAdjust); +} + + + +VOID +TrFilterDprIndicateReceiveFullMac( + IN PTR_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate a packet to + all bindings. The packet will be filtered so that only the + appropriate bindings will receive the packet. + + Called at DPC_LEVEL. + +Arguments: + + Filter - Pointer to the filter database. + + MacReceiveContext - A MAC supplied context value that must be + returned by the protocol if it calls MacTransferData. + + HeaderBuffer - A virtual address of the virtually contiguous + buffer containing the MAC header of the packet. + + HeaderBufferSize - An unsigned integer indicating the size of + the header buffer, in bytes. + + LookaheadBuffer - A virtual address of the virtually contiguous + buffer containing the first LookaheadBufferSize bytes of data + of the packet. The packet buffer is valid only within the current + call to the receive event handler. + + LookaheadBufferSize - An unsigned integer indicating the size of + the lookahead buffer, in bytes. + + PacketSize - An unsigned integer indicating the size of the received + packet, in bytes. This number has nothing to do with the lookahead + buffer, but indicates how large the arrived packet is so that a + subsequent MacTransferData request can be made to transfer the entire + packet as necessary. + +Return Value: + + None. + +--*/ + +{ + // + // The destination address in the lookahead buffer. + // + PCHAR DestinationAddress = (PCHAR)HeaderBuffer + 2; + + // + // The source address in the lookahead buffer. + // + PCHAR SourceAddress = (PCHAR)HeaderBuffer + 8; + + // + // Will hold the type of address that we know we've got. + // + UINT AddressType; + + // + // TRUE if the packet is source routing packet. + // + BOOLEAN IsSourceRouting; + + // + // TRUE if the packet is a MAC frame packet. + // + BOOLEAN IsMacFrame; + + // + // The functional address as a longword, if the packet + // is addressed to one. + // + TR_FUNCTIONAL_ADDRESS FunctionalAddress; + + // + // Will hold the status of indicating the receive packet. + // ZZZ For now this isn't used. + // + NDIS_STATUS StatusOfReceive; + + // + // Will hold the open being indicated. + // + PTR_BINDING_INFO LocalOpen, NextOpen; + + // + // Will hold the filter classes of the binding being indicated. + // + UINT BindingFilters; + + // + // Holds intersection of open filters and this packet's type + // + UINT IntersectionOfFilters; + + // + // If the packet is a runt packet, then only indicate to PROMISCUOUS + // + + if ((HeaderBufferSize >= 14) && (PacketSize != 0)) + { + UINT ResultOfAddressCheck; + + TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck); + + // + // Handle the directed packet case first + // + if (!ResultOfAddressCheck) + { + UINT IsNotOurs; + + // + // If it is a directed packet, then check if the combined packet + // filter is PROMISCUOUS, if it is check if it is directed towards + // us + // + IsNotOurs = FALSE; // Assume it is + if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | + NDIS_PACKET_TYPE_ALL_LOCAL | + NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) + { + TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress, + DestinationAddress, + &IsNotOurs); + } + + // + // Walk the directed list and indicate up the packets. + // + for (LocalOpen = Filter->DirectedList; + LocalOpen != NULL; + LocalOpen = NextOpen) + { + // + // Get the next open to look at. + // + NextOpen = LocalOpen->NextDirected; + + // + // Ignore if not directed to us and if the binding is not promiscuous + // + if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) && + IsNotOurs) + { + continue; + } + + LocalOpen->References++; + + NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + // + // Indicate the packet to the binding. + // + ProtocolFilterIndicateReceive(&StatusOfReceive, + LocalOpen->NdisBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize, + NdisMedium802_5); + + NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + LocalOpen->ReceivedAPacket = TRUE; + + --LocalOpen->References; + if (LocalOpen->References == 0) + { + // + // This binding is shutting down. We have to remove it. + // + trRemoveAndFreeBinding(Filter, LocalOpen, TRUE); + } + } + + return; + } + + TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting); + IsMacFrame = TR_IS_MAC_FRAME(HeaderBuffer); + + // + // First check if it *at least* has the functional address bit. + // + TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + // + // It is at least a functional address. Check to see if + // it is a broadcast address. + // + TR_IS_BROADCAST(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter); + + AddressType = NDIS_PACKET_TYPE_BROADCAST; + } + else + { + TR_IS_GROUP(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + AddressType = NDIS_PACKET_TYPE_GROUP; + } + else + { + AddressType = NDIS_PACKET_TYPE_FUNCTIONAL; + } + + RetrieveUlong(&FunctionalAddress, (DestinationAddress + 2)); + } + } + } + else + { + // Runt Packet + AddressType = NDIS_PACKET_TYPE_PROMISCUOUS; + IsSourceRouting = FALSE; + } + + + // + // At this point we know that the packet is either: + // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR) + // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR) + // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL + // + // Walk the broadcast/functional list and indicate up the packets. + // + // The packet is indicated if it meets the following criteria: + // + // if ((Binding is promiscuous) OR + // ((Packet is broadcast) AND (Binding is Broadcast)) OR + // ((Packet is functional) AND + // ((Binding is all-functional) OR + // ((Binding is functional) AND (binding using functional address)))) OR + // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR + // ((Packet is a macframe) AND (Binding wants mac frames)) OR + // ((Packet is a source routing packet) AND (Binding wants source routing packetss))) + // + for (LocalOpen = Filter->BFGList; + LocalOpen != NULL; + LocalOpen = NextOpen) + { + UINT LocalFilter = LocalOpen->PacketFilters; + UINT IntersectionOfFilters = LocalFilter & AddressType; + UINT IndexOfAddress; + + // + // Get the next open to look at. + // + NextOpen = LocalOpen->NextBFG; + + if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) || + + ((AddressType == NDIS_PACKET_TYPE_BROADCAST) && + (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) || + + ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) && + ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) || + ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) && + (FunctionalAddress & LocalOpen->FunctionalAddress)))) || + + ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) && + (LocalOpen->UsingGroupAddress) && + (FunctionalAddress == Filter->GroupAddress)) || + + ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) && + IsSourceRouting) || + + ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) && + IsMacFrame)) + { + LocalOpen->References++; + + NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + // + // Indicate the packet to the binding. + // + ProtocolFilterIndicateReceive(&StatusOfReceive, + LocalOpen->NdisBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize, + NdisMedium802_5); + + NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + LocalOpen->ReceivedAPacket = TRUE; + + if ((--(LocalOpen->References)) == 0) + { + // + // This binding is shutting down. + // + trRemoveAndFreeBinding(Filter, LocalOpen, TRUE); + } + } + } +} + + + +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 + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate a packet to + all bindings. The packet will be filtered so that only the + appropriate bindings will receive the packet. + +Arguments: + + Filter - Pointer to the filter database. + + MacReceiveContext - A MAC supplied context value that must be + returned by the protocol if it calls MacTransferData. + + HeaderBuffer - A virtual address of the virtually contiguous + buffer containing the MAC header of the packet. + + HeaderBufferSize - An unsigned integer indicating the size of + the header buffer, in bytes. + + LookaheadBuffer - A virtual address of the virtually contiguous + buffer containing the first LookaheadBufferSize bytes of data + of the packet. The packet buffer is valid only within the current + call to the receive event handler. + + LookaheadBufferSize - An unsigned integer indicating the size of + the lookahead buffer, in bytes. + + PacketSize - An unsigned integer indicating the size of the received + packet, in bytes. This number has nothing to do with the lookahead + buffer, but indicates how large the arrived packet is so that a + subsequent MacTransferData request can be made to transfer the entire + packet as necessary. + +Return Value: + + None. + +--*/ + +{ + KIRQL OldIrql; + + NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql); + + TrFilterDprIndicateReceiveFullMac(Filter, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize); + + NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql); +} + + +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 + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate a packet to + all bindings. The packet will be filtered so that only the + appropriate bindings will receive the packet. + + Called at DPC_LEVEL. + +Arguments: + + Filter - Pointer to the filter database. + + MacReceiveContext - A MAC supplied context value that must be + returned by the protocol if it calls MacTransferData. + + HeaderBuffer - A virtual address of the virtually contiguous + buffer containing the MAC header of the packet. + + HeaderBufferSize - An unsigned integer indicating the size of + the header buffer, in bytes. + + LookaheadBuffer - A virtual address of the virtually contiguous + buffer containing the first LookaheadBufferSize bytes of data + of the packet. The packet buffer is valid only within the current + call to the receive event handler. + + LookaheadBufferSize - An unsigned integer indicating the size of + the lookahead buffer, in bytes. + + PacketSize - An unsigned integer indicating the size of the received + packet, in bytes. This number has nothing to do with the lookahead + buffer, but indicates how large the arrived packet is so that a + subsequent MacTransferData request can be made to transfer the entire + packet as necessary. + +Return Value: + + None. + +--*/ + +{ + // + // The destination address in the lookahead buffer. + // + PCHAR DestinationAddress = (PCHAR)HeaderBuffer + 2; + + // + // The source address in the lookahead buffer. + // + PCHAR SourceAddress = (PCHAR)HeaderBuffer + 8; + + // + // Will hold the type of address that we know we've got. + // + UINT AddressType; + + // + // TRUE if the packet is source routing packet. + // + BOOLEAN IsSourceRouting; + + // + // TRUE if the packet is a MAC frame packet. + // + BOOLEAN IsMacFrame; + + // + // The functional address as a longword, if the packet + // is addressed to one. + // + TR_FUNCTIONAL_ADDRESS FunctionalAddress; + + // + // Will hold the status of indicating the receive packet. + // ZZZ For now this isn't used. + // + NDIS_STATUS StatusOfReceive; + + // + // Will hold the open being indicated. + // + PTR_BINDING_INFO LocalOpen, NextOpen; + + // + // Will hold the filter classes of the binding being indicated. + // + UINT BindingFilters; + + // + // Holds intersection of open filters and this packet's type + // + UINT IntersectionOfFilters; + + // + // If the packet is a runt packet, then only indicate to PROMISCUOUS + // + + if ((HeaderBufferSize >= 14) && (PacketSize != 0)) + { + UINT ResultOfAddressCheck; + + TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck); + + // + // Handle the directed packet case first + // + if (!ResultOfAddressCheck) + { + UINT IsNotOurs; + + // + // If it is a directed packet, then check if the combined packet + // filter is PROMISCUOUS, if it is check if it is directed towards + // us + // + IsNotOurs = FALSE; // Assume it is + if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | + NDIS_PACKET_TYPE_ALL_LOCAL | + NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) + { + TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress, + DestinationAddress, + &IsNotOurs); + } + + // + // Walk the directed list and indicate up the packets. + // + for (LocalOpen = Filter->DirectedList; + LocalOpen != NULL; + LocalOpen = NextOpen) + { + // + // Get the next open to look at. + // + NextOpen = LocalOpen->NextDirected; + + // + // Ignore if not directed to us and if the binding is not promiscuous + // + if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) && + IsNotOurs) + { + continue; + } + + LocalOpen->References++; + +// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock); + NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport); + + // + // Indicate the packet to the binding. + // + ProtocolFilterIndicateReceive(&StatusOfReceive, + LocalOpen->NdisBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize, + NdisMedium802_5); + +// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport); + + LocalOpen->ReceivedAPacket = TRUE; + + --LocalOpen->References; + if (LocalOpen->References == 0) + { + // + // This binding is shutting down. We have to remove it. + // + trRemoveAndFreeBinding(Filter, LocalOpen, TRUE); + } + } + + return; + } + + TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting); + IsMacFrame = TR_IS_MAC_FRAME(HeaderBuffer); + + // + // First check if it *at least* has the functional address bit. + // + TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + // + // It is at least a functional address. Check to see if + // it is a broadcast address. + // + TR_IS_BROADCAST(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter); + + AddressType = NDIS_PACKET_TYPE_BROADCAST; + } + else + { + TR_IS_GROUP(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + AddressType = NDIS_PACKET_TYPE_GROUP; + } + else + { + AddressType = NDIS_PACKET_TYPE_FUNCTIONAL; + } + + RetrieveUlong(&FunctionalAddress, (DestinationAddress + 2)); + } + } + } + else + { + // Runt Packet + AddressType = NDIS_PACKET_TYPE_PROMISCUOUS; + IsSourceRouting = FALSE; + } + + + // + // At this point we know that the packet is either: + // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR) + // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR) + // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL + // + // Walk the broadcast/functional list and indicate up the packets. + // + // The packet is indicated if it meets the following criteria: + // + // if ((Binding is promiscuous) OR + // ((Packet is broadcast) AND (Binding is Broadcast)) OR + // ((Packet is functional) AND + // ((Binding is all-functional) OR + // ((Binding is functional) AND (binding using functional address)))) OR + // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR + // ((Packet is a macframe) AND (Binding wants mac frames)) OR + // ((Packet is a source routing packet) AND (Binding wants source routing packetss))) + // + for (LocalOpen = Filter->BFGList; + LocalOpen != NULL; + LocalOpen = NextOpen) + { + UINT LocalFilter = LocalOpen->PacketFilters; + UINT IntersectionOfFilters = LocalFilter & AddressType; + UINT IndexOfAddress; + + // + // Get the next open to look at. + // + NextOpen = LocalOpen->NextBFG; + + if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) || + + ((AddressType == NDIS_PACKET_TYPE_BROADCAST) && + (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) || + + ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) && + ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) || + ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) && + (FunctionalAddress & LocalOpen->FunctionalAddress)))) || + + ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) && + (LocalOpen->UsingGroupAddress) && + (FunctionalAddress == Filter->GroupAddress)) || + + ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) && + IsSourceRouting) || + + ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) && + IsMacFrame)) + { + LocalOpen->References++; + +// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock); + NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport); + + // + // Indicate the packet to the binding. + // + ProtocolFilterIndicateReceive(&StatusOfReceive, + LocalOpen->NdisBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize, + NdisMedium802_5); + +// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport); + + LocalOpen->ReceivedAPacket = TRUE; + + if ((--(LocalOpen->References)) == 0) + { + // + // This binding is shutting down. + // + trRemoveAndFreeBinding(Filter, LocalOpen, TRUE); + } + } + } +} + + +VOID +TrFilterDprIndicateReceivePacket( + IN PNDIS_MINIPORT_BLOCK Miniport, + IN PPNDIS_PACKET PacketArray, + IN UINT NumberOfPackets +) + +/*++ + +Routine Description: + + This routine is called by the Miniport to indicate packets to + all bindings. The packets will be filtered so that only the + appropriate bindings will receive the individual packets. + This is the code path for ndis 4.0 miniport drivers. + +Arguments: + + Miniport - The Miniport block. + + PacketArray - An array of Packets indicated by the miniport. + + NumberOfPackets - Self-explanatory. + +Return Value: + + None. + +--*/ +{ + // + // The Filter of interest + // + PTR_FILTER Filter = Miniport->TrDB; + + // + // Current packet being processed + // + PPNDIS_PACKET pPktArray = PacketArray; + + // + // Pointer to the buffer in the ndispacket + // + PNDIS_BUFFER Buffer; + + // + // Pointer to the 1st segment of the buffer, points to dest address + // + PUCHAR Address; + + // + // Total packet length + // + UINT i, LASize, PacketSize, NumIndicates = 0; + + // + // The destination address in the lookahead buffer. + // + PCHAR DestinationAddress; + + // + // The source address in the lookahead buffer. + // + PCHAR SourceAddress; + + // + // Will hold the type of address that we know we've got. + // + UINT AddressType; + + // + // TRUE if the packet is source routing packet. + // + BOOLEAN IsSourceRouting; + + // + // TRUE if the packet is a MAC frame packet. + // + BOOLEAN IsMacFrame; + + // + // The functional address as a longword, if the packet + // is addressed to one. + // + TR_FUNCTIONAL_ADDRESS FunctionalAddress; + + // + // Will hold the status of indicating the receive packet. + // ZZZ For now this isn't used. + // + NDIS_STATUS StatusOfReceive; + + // + // Will hold the filter classes of the binding being indicated. + // + UINT BindingFilters; + + // + // Decides whether we use the protocol's revpkt handler or fall + // back to old rcvindicate handler + // + BOOLEAN fFallBack, fPmode, FixRef; + + // + // Will hold the open being indicated. + // + PTR_BINDING_INFO LocalOpen, NextOpen; + PNDIS_OPEN_BLOCK pOpenBlock; \ + + MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID); + + // Walk all the packets + for (i = 0; i < NumberOfPackets; i++, pPktArray++) + { + PNDIS_PACKET Packet = *pPktArray; + PNDIS_PACKET_OOB_DATA pOob; + + ASSERT(Packet != NULL); + + pOob = NDIS_OOB_DATA_FROM_PACKET(Packet); + + NdisGetFirstBufferFromPacket(Packet, + &Buffer, + &Address, + &LASize, + &PacketSize); + ASSERT(Buffer != NULL); + + PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0; + PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport; + + // + // Set the status here that nobody is holding the packet. This will get + // overwritten by the real status from the protocol. Pay heed to what + // the miniport is saying. + // + if (pOob->Status != NDIS_STATUS_RESOURCES) + { + pOob->Status = NDIS_STATUS_SUCCESS; + PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --; + fFallBack = FALSE; + FixRef = TRUE; + } + else + { + fFallBack = TRUE; + FixRef = FALSE; + } + + // + // Ensure that we force re-calculation. + // + Packet->Private.ValidCounts = FALSE; + + // + // The destination address in the lookahead buffer. + // + DestinationAddress = (PCHAR)Address + 2; + + // + // The source address in the lookahead buffer. + // + SourceAddress = (PCHAR)Address + 8; + + // Determine if there is source routing info and compute hdr len +#if DBG + { + UINT HdrSize; + + HdrSize = 14; + if (Address[8] & 0x80) + { + HdrSize += (Address[14] & 0x1F); + } + ASSERT(HdrSize == pOob->HeaderSize); + } +#endif + // + // A quick check for Runt packets. These are only indicated to Promiscuous bindings + // + if (PacketSize >= pOob->HeaderSize) + { + UINT ResultOfAddressCheck; + + // + // If it is a directed packet, then check if the combined packet + // filter is PROMISCUOUS, if it is check if it is directed towards us + // + TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck); + + // + // Handle the directed packet case first + // + if (!ResultOfAddressCheck) + { + UINT IsNotOurs; + + // + // If it is a directed packet, then check if the combined packet + // filter is PROMISCUOUS, if it is check if it is directed towards + // us + // + IsNotOurs = FALSE; // Assume it is + if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | + NDIS_PACKET_TYPE_ALL_LOCAL | + NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) + { + TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress, + DestinationAddress, + &IsNotOurs); + } + + // + // We definitely have a directed packet so lets indicate it now. + // + // Walk the directed list and indicate up the packets. + // + for (LocalOpen = Filter->DirectedList; + LocalOpen != NULL; + LocalOpen = NextOpen) + { + // + // Get the next open to look at. + // + NextOpen = LocalOpen->NextDirected; + + // + // Ignore if not directed to us and if the binding is not promiscuous + // + if (((LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) == 0) && + IsNotOurs) + { + continue; + } + + pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext); + LocalOpen->ReceivedAPacket = TRUE; + LocalOpen->References++; + NumIndicates ++; + + fPmode = (LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | + NDIS_PACKET_TYPE_ALL_LOCAL)) ? + TRUE : FALSE; + IndicateToProtocol(Miniport, + Filter, + pOpenBlock, + Packet, + Address, + PacketSize, + pOob->HeaderSize, + &fFallBack, + fPmode, + NdisMedium802_5); + + LocalOpen->References--; + if (LocalOpen->References == 0) + { + // + // This binding is shutting down. We have to remove it. + // + trRemoveAndFreeBinding(Filter, LocalOpen, TRUE); + } + } + + if (FixRef) + { + PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++; + if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0) + { + NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING); + } + } + continue; // Done with this packet + } + + TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting); + IsMacFrame = TR_IS_MAC_FRAME(Address); + + // + // First check if it *at least* has the functional address bit. + // + TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + // + // It is at least a functional address. Check to see if + // it is a broadcast address. + // + TR_IS_BROADCAST(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter); + + AddressType = NDIS_PACKET_TYPE_BROADCAST; + } + else + { + TR_IS_GROUP(DestinationAddress, &ResultOfAddressCheck); + if (ResultOfAddressCheck) + { + AddressType = NDIS_PACKET_TYPE_GROUP; + } + else + { + AddressType = NDIS_PACKET_TYPE_FUNCTIONAL; + } + + RetrieveUlong(&FunctionalAddress, (DestinationAddress + 2)); + } + } + } + else + { + // Runt Packet + AddressType = NDIS_PACKET_TYPE_PROMISCUOUS; + IsSourceRouting = FALSE; + } + + // + // At this point we know that the packet is either: + // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR) + // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR) + // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL + // + // Walk the broadcast/functional list and indicate up the packets. + // + // The packet is indicated if it meets the following criteria: + // + // if ((Binding is promiscuous) OR + // ((Packet is broadcast) AND (Binding is Broadcast)) OR + // ((Packet is functional) AND + // ((Binding is all-functional) OR + // ((Binding is functional) AND (binding using functional address)))) OR + // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR + // ((Packet is a macframe) AND (Binding wants mac frames)) OR + // ((Packet is a source routing packet) AND (Binding wants source routing packetss))) + // + for (LocalOpen = Filter->BFGList; + LocalOpen != NULL; + LocalOpen = NextOpen) + { + UINT LocalFilter = LocalOpen->PacketFilters; + UINT IntersectionOfFilters = LocalFilter & AddressType; + UINT IndexOfAddress; + + // + // Get the next open to look at. + // + NextOpen = LocalOpen->NextBFG; + + if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) || + + ((AddressType == NDIS_PACKET_TYPE_BROADCAST) && + (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) || + + ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) && + ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) || + ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) && + (FunctionalAddress & LocalOpen->FunctionalAddress)))) || + + ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) && + (LocalOpen->UsingGroupAddress)) || + + ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) && + IsSourceRouting) || + + ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) && + IsMacFrame)) + { + pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext); + LocalOpen->ReceivedAPacket = TRUE; + LocalOpen->References++; + NumIndicates ++; + + fPmode = (LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ? + TRUE : FALSE; + IndicateToProtocol(Miniport, + Filter, + pOpenBlock, + Packet, + Address, + PacketSize, + pOob->HeaderSize, + &fFallBack, + fPmode, + NdisMedium802_5); + + LocalOpen->References--; + if (LocalOpen->References == 0) + { + // + // This binding is shutting down. + // + trRemoveAndFreeBinding(Filter, LocalOpen, TRUE); + } + } + } + + if (FixRef) + { + PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++; + if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0) + { + NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING); + } + } + } + + MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID); + + if (NumIndicates > 0) + { + TrFilterDprIndicateReceiveComplete(Filter); + } +} + + + +VOID +TrFilterDprIndicateReceiveCompleteFullMac( + IN PTR_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate that the receive + process is done and to indicate to all protocols which received + a packet that receive is complete. + + Called at DPC_LEVEL. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ + +{ + // + // Pointer to currently indicated binding. + // + PTR_BINDING_INFO LocalOpen, NextOpen; + + // + // We need to aquire the filter exclusively while we're finding + // bindings to indicate to. + // + for (LocalOpen = Filter->OpenList; + LocalOpen != NULL; + LocalOpen = NextOpen) + { + LocalOpen->References++; + NextOpen = LocalOpen->NextOpen; + + if (LocalOpen->ReceivedAPacket) + { + // + // Indicate the binding. + // + + LocalOpen->ReceivedAPacket = FALSE; + + NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + } + + if ((--(LocalOpen->References)) == 0) + { + // + // This binding is shutting down. + // + trRemoveBindingFromLists(Filter, LocalOpen); + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + Filter->CloseAction(LocalOpen->MacBindingHandle); + + TR_FILTER_FREE_OPEN(Filter, LocalOpen); + } + } +} + + + +VOID +TrFilterIndicateReceiveComplete( + IN PTR_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate that the receive + process is done and to indicate to all protocols which received + a packet that receive is complete. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ + +{ + KIRQL OldIrql; + + NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql); + TrFilterDprIndicateReceiveCompleteFullMac(Filter); + NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql); +} + + +VOID +TrFilterDprIndicateReceiveComplete( + IN PTR_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate that the receive + process is done and to indicate to all protocols which received + a packet that receive is complete. + + Called at DPC_LEVEL. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ + +{ + // + // Pointer to currently indicated binding. + // + PTR_BINDING_INFO LocalOpen, NextOpen; + + // + // We need to aquire the filter exclusively while we're finding + // bindings to indicate to. + // + for (LocalOpen = Filter->OpenList; + LocalOpen != NULL; + LocalOpen = NextOpen) + { + LocalOpen->References++; + NextOpen = LocalOpen->NextOpen; + + if (LocalOpen->ReceivedAPacket) + { + // + // Indicate the binding. + // + + LocalOpen->ReceivedAPacket = FALSE; + +// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock); + NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + +// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport); + } + + if ((--(LocalOpen->References)) == 0) + { + // + // This binding is shutting down. + // + trRemoveBindingFromLists(Filter, LocalOpen); + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + Filter->CloseAction(LocalOpen->MacBindingHandle); + + TR_FILTER_FREE_OPEN(Filter, LocalOpen); + } + } +} + + +BOOLEAN +TrShouldAddressLoopBack( + IN PTR_FILTER Filter, + IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS], + IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS] + ) + +/*++ + +Routine Description: + + Do a quick check to see whether the input address should + loopback. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + + NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE + EQUALS DESTINATION. + +Arguments: + + Filter - Pointer to the filter database. + + Address - A network address to check for loopback. + + +Return Value: + + Returns TRUE if the address is *likely* to need loopback. It + will return FALSE if there is *no* chance that the address would + require loopback. + +--*/ +{ + BOOLEAN fLoopback, fSelfDirected; + + TrShouldAddressLoopBackMacro(Filter, + DestinationAddress, + SourceAddress, + &fLoopback, + &fSelfDirected); + + return(fLoopback); +} + + |