You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1815 lines
57 KiB
1815 lines
57 KiB
/*++
|
|
|
|
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 UCHAR NullFunctionalAddress[4] = { 0x00 };
|
|
|
|
|
|
//
|
|
// Maximum number of supported opens
|
|
//
|
|
#define TR_FILTER_MAX_OPENS 32
|
|
|
|
|
|
#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); \
|
|
} \
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
TrCreateFilter(
|
|
IN PUCHAR AdapterAddress,
|
|
OUT PTR_FILTER * Filter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to create and initialize the filter database.
|
|
|
|
Arguments:
|
|
|
|
AdapterAddress - the address of the adapter associated with this filter
|
|
database.
|
|
|
|
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;
|
|
BOOLEAN rc = FALSE;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Allocate the database and initialize it.
|
|
//
|
|
*Filter = LocalFilter = ALLOC_FROM_POOL(sizeof(TR_FILTER), NDIS_TAG_FILTER);
|
|
if (LocalFilter != NULL)
|
|
{
|
|
ZeroMemory(LocalFilter, sizeof(TR_FILTER));
|
|
//1 what is this LocalFilter->NumOpens?
|
|
LocalFilter->NumOpens ++;
|
|
TrReferencePackage();
|
|
TR_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress);
|
|
INITIALIZE_SPIN_LOCK(&LocalFilter->BindListLock.SpinLock);
|
|
rc = TRUE;
|
|
}
|
|
} while (FALSE);
|
|
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
|
|
--*/
|
|
{
|
|
//1 check to see if we should free memory for group addresses
|
|
ASSERT(Filter->OpenList == NULL);
|
|
|
|
FREE_POOL(Filter);
|
|
TrDereferencePackage();
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
TrDeleteFilterOpenAdapter(
|
|
IN PTR_FILTER Filter,
|
|
IN NDIS_HANDLE NdisFilterHandle
|
|
)
|
|
/*++
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS StatusToReturn;
|
|
PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
|
|
|
|
//
|
|
// Set the packet filter to NONE.
|
|
//
|
|
StatusToReturn = XFilterAdjust(Filter,
|
|
NdisFilterHandle,
|
|
(UINT)0,
|
|
FALSE);
|
|
if ((NDIS_STATUS_SUCCESS == StatusToReturn) ||
|
|
(NDIS_STATUS_PENDING == StatusToReturn))
|
|
{
|
|
NDIS_STATUS StatusToReturn2;
|
|
|
|
//
|
|
// Clear the functional address.
|
|
//
|
|
StatusToReturn2 = TrChangeFunctionalAddress(
|
|
Filter,
|
|
NdisFilterHandle,
|
|
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,
|
|
NullFunctionalAddress,
|
|
FALSE);
|
|
if (StatusToReturn2 != NDIS_STATUS_SUCCESS)
|
|
{
|
|
StatusToReturn = StatusToReturn2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
|
|
(StatusToReturn == NDIS_STATUS_PENDING) ||
|
|
(StatusToReturn == NDIS_STATUS_RESOURCES))
|
|
{
|
|
//
|
|
// 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.
|
|
//
|
|
XRemoveAndFreeBinding(Filter, LocalOpen);
|
|
}
|
|
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);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
TrChangeFunctionalAddress(
|
|
IN PTR_FILTER Filter,
|
|
IN NDIS_HANDLE NdisFilterHandle,
|
|
IN UCHAR 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
|
|
|
|
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;
|
|
|
|
|
|
UNREFERENCED_PARAMETER(Set);
|
|
|
|
//
|
|
// 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 = NDIS_STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
StatusOfAdjust = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
return(StatusOfAdjust);
|
|
}
|
|
|
|
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
|
|
TrChangeGroupAddress(
|
|
IN PTR_FILTER Filter,
|
|
IN NDIS_HANDLE NdisFilterHandle,
|
|
IN UCHAR 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.
|
|
|
|
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;
|
|
|
|
UNREFERENCED_PARAMETER(Set);
|
|
|
|
//
|
|
// 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;
|
|
|
|
if (GroupAddress == 0)
|
|
{
|
|
LocalOpen->UsingGroupAddress = FALSE;
|
|
Filter->GroupReferences = 0;
|
|
}
|
|
else
|
|
{
|
|
LocalOpen->UsingGroupAddress = TRUE;
|
|
Filter->GroupReferences = 1;
|
|
}
|
|
|
|
return(NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
|
|
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
|
|
FASTCALL
|
|
ndisMSetFunctionalAddress(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_REQUEST Request
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
UINT FunctionalAddress;
|
|
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("==>ndisMSetFunctionalAddress\n"));
|
|
|
|
//
|
|
// Verify the media type.
|
|
//
|
|
if (Miniport->MediaType != NdisMedium802_5)
|
|
{
|
|
Request->DATA.SET_INFORMATION.BytesRead = 0;
|
|
Request->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("ndisMSetFunctionalAddress: Invalid media type\n"));
|
|
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("<==ndisMSetFunctionalAddress: 0x%x\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Verify the buffer length that was passed in.
|
|
//
|
|
VERIFY_SET_PARAMETERS(Request, sizeof(FunctionalAddress), Status);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("<==ndisMSetFunctionalAddress: 0x%x\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// If this request is because of an open that is closing then we
|
|
// have already adjusted the settings and we just need to
|
|
// make sure that the adapter has the new settings.
|
|
//
|
|
if (MINIPORT_TEST_FLAG(PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open, fMINIPORT_OPEN_CLOSING))
|
|
{
|
|
//
|
|
// By setting the Status to NDIS_STATUS_PENDING we will call
|
|
// down to the miniport's SetInformationHandler below.
|
|
//
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Call the filter library to set the functional address.
|
|
//
|
|
Status = TrChangeFunctionalAddress(
|
|
Miniport->TrDB,
|
|
PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
|
|
(PUCHAR)(Request->DATA.SET_INFORMATION.InformationBuffer),
|
|
TRUE);
|
|
}
|
|
|
|
//
|
|
// If the filter library returned NDIS_STATUS_PENDING then we
|
|
// need to call down to the miniport driver.
|
|
//
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
//
|
|
// Get the new combined functional address from the filter library
|
|
// and save it in a buffer that will stick around.
|
|
//
|
|
FunctionalAddress = BYTE_SWAP_ULONG(TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB));
|
|
Miniport->RequestBuffer = FunctionalAddress;
|
|
|
|
//
|
|
// Call the miniport driver.
|
|
//
|
|
SAVE_REQUEST_BUF(Miniport, Request, &Miniport->RequestBuffer, sizeof(FunctionalAddress));
|
|
MINIPORT_SET_INFO(Miniport,
|
|
Request,
|
|
&Status);
|
|
}
|
|
|
|
//
|
|
// If we succeeded then update the request.
|
|
//
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
RESTORE_REQUEST_BUF(Miniport, Request);
|
|
if (NDIS_STATUS_SUCCESS == Status)
|
|
{
|
|
Request->DATA.SET_INFORMATION.BytesRead = Request->DATA.SET_INFORMATION.InformationBufferLength;
|
|
}
|
|
else
|
|
{
|
|
Request->DATA.SET_INFORMATION.BytesRead = 0;
|
|
Request->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
}
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("<==ndisMSetFunctionalAddress: 0x%x\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisMSetGroupAddress(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_REQUEST Request
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
UINT GroupAddress;
|
|
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("==>ndisMSetGroupAddress\n"));
|
|
|
|
//
|
|
// Verify the media type.
|
|
//
|
|
if (Miniport->MediaType != NdisMedium802_5)
|
|
{
|
|
Request->DATA.SET_INFORMATION.BytesRead = 0;
|
|
Request->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("ndisMSetGroupAddress: invalid media type\n"));
|
|
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("<==ndisMSetGroupAddress: 0x%x\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Verify the information buffer length.
|
|
//
|
|
VERIFY_SET_PARAMETERS(Request, sizeof(GroupAddress), Status);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("<==ndisMSetGroupAddress: 0x%x\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// If this request is because of an open that is closing then we
|
|
// have already adjusted the settings and we just need to
|
|
// make sure that the adapter has the new settings.
|
|
//
|
|
if (MINIPORT_TEST_FLAG(PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open, fMINIPORT_OPEN_CLOSING))
|
|
{
|
|
//
|
|
// By setting the Status to NDIS_STATUS_PENDING we will call
|
|
// down to the miniport's SetInformationHandler below.
|
|
//
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Call the filter library to set the new group address.
|
|
//
|
|
Status = TrChangeGroupAddress(
|
|
Miniport->TrDB,
|
|
PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
|
|
(PUCHAR)(Request->DATA.SET_INFORMATION.InformationBuffer),
|
|
TRUE);
|
|
}
|
|
|
|
//
|
|
// If the filter library returned NDIS_STATUS_PENDING then we
|
|
// need to call down to the miniport driver.
|
|
//
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
//
|
|
// Get the new group address from the filter library
|
|
// and save it in a buffer that will stick around.
|
|
//
|
|
GroupAddress = BYTE_SWAP_ULONG(TR_QUERY_FILTER_GROUP(Miniport->TrDB));
|
|
Miniport->RequestBuffer = GroupAddress;
|
|
|
|
//
|
|
// Call the miniport driver with the new group address.
|
|
//
|
|
SAVE_REQUEST_BUF(Miniport, Request, &Miniport->RequestBuffer, sizeof(GroupAddress));
|
|
MINIPORT_SET_INFO(Miniport,
|
|
Request,
|
|
&Status);
|
|
}
|
|
|
|
//
|
|
// If we succeeded then update the request.
|
|
//
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
RESTORE_REQUEST_BUF(Miniport, Request);
|
|
if (NDIS_STATUS_SUCCESS == Status)
|
|
{
|
|
Request->DATA.SET_INFORMATION.BytesRead =
|
|
Request->DATA.SET_INFORMATION.InformationBufferLength;
|
|
}
|
|
else
|
|
{
|
|
Request->DATA.SET_INFORMATION.BytesRead = 0;
|
|
Request->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
}
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("<==ndisMSetGroupAddress: 0x%x\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
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.
|
|
//
|
|
PUCHAR DestinationAddress = (PUCHAR)HeaderBuffer + 2;
|
|
|
|
//
|
|
// The source address in the lookahead buffer.
|
|
//
|
|
PUCHAR SourceAddress = (PUCHAR)HeaderBuffer + 8;
|
|
|
|
//
|
|
// Will hold the type of address that we know we've got.
|
|
//
|
|
UINT AddressType = 0;
|
|
|
|
//
|
|
// 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 = 0;
|
|
|
|
//
|
|
// 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;
|
|
|
|
LOCK_STATE LockState;
|
|
|
|
//
|
|
// Holds intersection of open filters and this packet's type
|
|
//
|
|
UINT IntersectionOfFilters;
|
|
|
|
//
|
|
// if filter is null, the adapter is indicating too early
|
|
//
|
|
if (Filter == NULL)
|
|
{
|
|
#if DBG
|
|
DbgPrint("Driver is indicating packets too early\n");
|
|
if (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)
|
|
{
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
if (!MINIPORT_TEST_FLAG(Filter->Miniport, fMINIPORT_MEDIA_CONNECTED))
|
|
{
|
|
NDIS_WARN(TRUE,
|
|
Filter->Miniport,
|
|
NDIS_GFLAG_WARN_LEVEL_1,
|
|
("TrFilterDprIndicateReceive: Miniport %p IndicateReceives with media disconnected\n",
|
|
Filter->Miniport));
|
|
return;
|
|
}
|
|
|
|
ASSERT_MINIPORT_LOCKED(Filter->Miniport);
|
|
|
|
READ_LOCK_FILTER(Filter->Miniport, Filter, &LockState);
|
|
|
|
#if DBG
|
|
Filter->Miniport->cDpcRcvIndications++;
|
|
Filter->Miniport->cDpcRcvIndicationCalls++;
|
|
#endif
|
|
|
|
//
|
|
// 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;
|
|
|
|
DIRECTED_PACKETS_IN(Filter->Miniport);
|
|
DIRECTED_BYTES_IN(Filter->Miniport, PacketSize);
|
|
|
|
//
|
|
// 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->OpenList;
|
|
LocalOpen != NULL;
|
|
LocalOpen = NextOpen)
|
|
{
|
|
//
|
|
// Get the next open to look at.
|
|
//
|
|
NextOpen = LocalOpen->NextOpen;
|
|
|
|
//
|
|
// Ignore if not directed to us and if the binding is not promiscuous
|
|
//
|
|
if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
|
|
(IsNotOurs ||
|
|
((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_DIRECTED) == 0)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Indicate the packet to the binding.
|
|
//
|
|
ProtocolFilterIndicateReceive(&StatusOfReceive,
|
|
LocalOpen->NdisBindingHandle,
|
|
MacReceiveContext,
|
|
HeaderBuffer,
|
|
HeaderBufferSize,
|
|
LookaheadBuffer,
|
|
LookaheadBufferSize,
|
|
PacketSize,
|
|
NdisMedium802_5);
|
|
|
|
LocalOpen->ReceivedAPacket = TRUE;
|
|
}
|
|
|
|
READ_UNLOCK_FILTER(Filter->Miniport, Filter, &LockState);
|
|
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;
|
|
IsMacFrame = 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->OpenList;
|
|
LocalOpen != NULL;
|
|
LocalOpen = NextOpen)
|
|
{
|
|
UINT LocalFilter = LocalOpen->PacketFilters;
|
|
|
|
IntersectionOfFilters = LocalFilter & AddressType;
|
|
|
|
//
|
|
// Get the next open to look at.
|
|
//
|
|
NextOpen = LocalOpen->NextOpen;
|
|
|
|
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))
|
|
{
|
|
//
|
|
// Indicate the packet to the binding.
|
|
//
|
|
ProtocolFilterIndicateReceive(&StatusOfReceive,
|
|
LocalOpen->NdisBindingHandle,
|
|
MacReceiveContext,
|
|
HeaderBuffer,
|
|
HeaderBufferSize,
|
|
LookaheadBuffer,
|
|
LookaheadBufferSize,
|
|
PacketSize,
|
|
NdisMedium802_5);
|
|
|
|
LocalOpen->ReceivedAPacket = TRUE;
|
|
}
|
|
}
|
|
|
|
READ_UNLOCK_FILTER(Filter->Miniport, Filter, &LockState);
|
|
}
|
|
|
|
|
|
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;
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_PACKET_OOB_DATA pOob;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
PUCHAR DestinationAddress;
|
|
|
|
//
|
|
// The source address in the lookahead buffer.
|
|
//
|
|
PCHAR SourceAddress;
|
|
|
|
//
|
|
// Will hold the type of address that we know we've got.
|
|
//
|
|
UINT AddressType = 0;
|
|
|
|
//
|
|
// 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 = 0;
|
|
|
|
LOCK_STATE LockState;
|
|
|
|
//
|
|
// Decides whether we use the protocol's revpkt handler or fall
|
|
// back to old rcvindicate handler
|
|
//
|
|
BOOLEAN fFallBack, fPmode;
|
|
|
|
//
|
|
// Will hold the open being indicated.
|
|
//
|
|
PTR_BINDING_INFO LocalOpen, NextOpen;
|
|
PNDIS_OPEN_BLOCK pOpenBlock;
|
|
PNDIS_STACK_RESERVED NSR;
|
|
|
|
#ifdef TRACK_RECEIVED_PACKETS
|
|
ULONG OrgPacketStackLocation;
|
|
PETHREAD CurThread = PsGetCurrentThread();
|
|
#endif
|
|
|
|
|
|
ASSERT_MINIPORT_LOCKED(Miniport);
|
|
|
|
READ_LOCK_FILTER(Miniport, Filter, &LockState);
|
|
|
|
#if DBG
|
|
Miniport->cDpcRcvIndications += NumberOfPackets;
|
|
Miniport->cDpcRcvIndicationCalls++;
|
|
#endif
|
|
|
|
//
|
|
// Walk all the packets
|
|
//
|
|
for (i = 0; i < NumberOfPackets; i++, pPktArray++)
|
|
{
|
|
do
|
|
{
|
|
Packet = *pPktArray;
|
|
ASSERT(Packet != NULL);
|
|
#ifdef TRACK_RECEIVED_PACKETS
|
|
OrgPacketStackLocation = CURR_STACK_LOCATION(Packet);
|
|
#endif
|
|
PUSH_PACKET_STACK(Packet);
|
|
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
|
|
|
|
ASSERT(NSR->RefCount == 0);
|
|
//1 this does not check for current stack location for non-im drivers
|
|
//1 to be -1 as we do for Ethernet
|
|
if (NSR->RefCount != 0)
|
|
{
|
|
BAD_MINIPORT(Miniport, "Indicating packet not owned by it");
|
|
|
|
KeBugCheckEx(BUGCODE_NDIS_DRIVER,
|
|
0x12,
|
|
(ULONG_PTR)Miniport,
|
|
(ULONG_PTR)Packet,
|
|
(ULONG_PTR)PacketArray);
|
|
}
|
|
|
|
pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
|
|
|
|
NdisGetFirstBufferFromPacket(Packet,
|
|
&Buffer,
|
|
&Address,
|
|
&LASize,
|
|
&PacketSize);
|
|
ASSERT(Buffer != NULL);
|
|
|
|
//
|
|
// Set context in the packet so that NdisReturnPacket can do the right thing
|
|
//
|
|
NDIS_INITIALIZE_RCVD_PACKET(Packet, NSR, 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) &&
|
|
!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING))
|
|
{
|
|
pOob->Status = NDIS_STATUS_SUCCESS;
|
|
fFallBack = FALSE;
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
if ((pOob->Status != NDIS_STATUS_RESOURCES) &&
|
|
MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING))
|
|
{
|
|
DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR,
|
|
("Miniport going into D3, not indicating chained receives\n"));
|
|
}
|
|
#endif
|
|
fFallBack = TRUE;
|
|
}
|
|
|
|
//1 what are the first two bytes in token-ring header
|
|
//
|
|
// The destination address in the lookahead buffer.
|
|
//
|
|
DestinationAddress = (PUCHAR)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 (!MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_IS_LOOPBACK))
|
|
{
|
|
DIRECTED_PACKETS_IN(Miniport);
|
|
DIRECTED_BYTES_IN(Miniport, PacketSize);
|
|
}
|
|
|
|
//
|
|
// 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->OpenList;
|
|
LocalOpen != NULL;
|
|
LocalOpen = NextOpen)
|
|
{
|
|
//
|
|
// Get the next open to look at.
|
|
//
|
|
NextOpen = LocalOpen->NextOpen;
|
|
|
|
//
|
|
// Ignore if not directed to us and if the binding is not promiscuous
|
|
// Or if this is a loopback packet and this protocol specifically asked
|
|
// us not to loop it back
|
|
//
|
|
fPmode = (LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS |
|
|
NDIS_PACKET_TYPE_ALL_LOCAL)) ?
|
|
TRUE : FALSE;
|
|
|
|
|
|
if (!fPmode &&
|
|
(IsNotOurs ||
|
|
((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_DIRECTED) == 0)))
|
|
{
|
|
|
|
continue;
|
|
}
|
|
|
|
if ((NdisGetPacketFlags(Packet) & NDIS_FLAGS_DONT_LOOPBACK) &&
|
|
(LOOPBACK_OPEN_IN_PACKET(Packet) == LocalOpen->NdisBindingHandle))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingHandle);
|
|
LocalOpen->ReceivedAPacket = TRUE;
|
|
NumIndicates ++;
|
|
|
|
IndicateToProtocol(Miniport,
|
|
Filter,
|
|
pOpenBlock,
|
|
Packet,
|
|
NSR,
|
|
Address,
|
|
PacketSize,
|
|
pOob->HeaderSize,
|
|
&fFallBack,
|
|
fPmode,
|
|
NdisMedium802_5);
|
|
}
|
|
|
|
// Done with this packet
|
|
break; // out of do { } while (FALSE);
|
|
}
|
|
|
|
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;
|
|
IsMacFrame = 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->OpenList;
|
|
LocalOpen != NULL;
|
|
LocalOpen = NextOpen)
|
|
{
|
|
UINT LocalFilter = LocalOpen->PacketFilters;
|
|
UINT IntersectionOfFilters = LocalFilter & AddressType;
|
|
|
|
//
|
|
// Get the next open to look at.
|
|
//
|
|
NextOpen = LocalOpen->NextOpen;
|
|
|
|
if ((NdisGetPacketFlags(Packet) & NDIS_FLAGS_DONT_LOOPBACK) &&
|
|
(LOOPBACK_OPEN_IN_PACKET(Packet) == LocalOpen->NdisBindingHandle))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
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))
|
|
{
|
|
pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingHandle);
|
|
LocalOpen->ReceivedAPacket = TRUE;
|
|
NumIndicates ++;
|
|
|
|
fPmode = (LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
|
|
TRUE : FALSE;
|
|
|
|
IndicateToProtocol(Miniport,
|
|
Filter,
|
|
pOpenBlock,
|
|
Packet,
|
|
NSR,
|
|
Address,
|
|
PacketSize,
|
|
pOob->HeaderSize,
|
|
&fFallBack,
|
|
fPmode,
|
|
NdisMedium802_5);
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Tackle refcounts now
|
|
//
|
|
TACKLE_REF_COUNT(Miniport, Packet, NSR, pOob);
|
|
}
|
|
|
|
if (NumIndicates > 0)
|
|
{
|
|
for (LocalOpen = Filter->OpenList;
|
|
LocalOpen != NULL;
|
|
LocalOpen = NextOpen)
|
|
{
|
|
NextOpen = LocalOpen->NextOpen;
|
|
|
|
if (LocalOpen->ReceivedAPacket)
|
|
{
|
|
//
|
|
// Indicate the binding.
|
|
//
|
|
LocalOpen->ReceivedAPacket = FALSE;
|
|
|
|
FilterIndicateReceiveComplete(LocalOpen->NdisBindingHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
READ_UNLOCK_FILTER(Miniport, Filter, &LockState);
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
PTR_BINDING_INFO LocalOpen, NextOpen;
|
|
LOCK_STATE LockState;
|
|
|
|
ASSERT_MINIPORT_LOCKED(Filter->Miniport);
|
|
|
|
READ_LOCK_FILTER(Filter->Miniport, Filter, &LockState);
|
|
|
|
//
|
|
// We need to aquire the filter exclusively while we're finding
|
|
// bindings to indicate to.
|
|
//
|
|
for (LocalOpen = Filter->OpenList;
|
|
LocalOpen != NULL;
|
|
LocalOpen = NextOpen)
|
|
{
|
|
NextOpen = LocalOpen->NextOpen;
|
|
|
|
if (LocalOpen->ReceivedAPacket)
|
|
{
|
|
//
|
|
// Indicate the binding.
|
|
//
|
|
LocalOpen->ReceivedAPacket = FALSE;
|
|
|
|
FilterIndicateReceiveComplete(LocalOpen->NdisBindingHandle);
|
|
}
|
|
}
|
|
|
|
READ_UNLOCK_FILTER(Filter->Miniport, Filter, &LockState);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
TrShouldAddressLoopBack(
|
|
IN PTR_FILTER Filter,
|
|
IN UCHAR DestinationAddress[TR_LENGTH_OF_ADDRESS],
|
|
IN UCHAR 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);
|
|
}
|
|
|