diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/lsl/lslmlid.c | 2085 |
1 files changed, 2085 insertions, 0 deletions
diff --git a/private/ntos/ndis/lsl/lslmlid.c b/private/ntos/ndis/lsl/lslmlid.c new file mode 100644 index 000000000..a1f0b1b17 --- /dev/null +++ b/private/ntos/ndis/lsl/lslmlid.c @@ -0,0 +1,2085 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + lslmlid.c + +Abstract: + + This file contains all the MLID interface routines to the LSL + +Author: + + Sean Selitrennikoff (SeanSe) 3-8-93 + +Environment: + + Kernel Mode. + +Revision History: + +--*/ + +#include <ndis.h> +#include "lsl.h" +#include "frames.h" +#include "lslmlid.h" +#include "mlid.h" + + +// +// A global which has pointers to the functions in this file. Used for registering +// with the LSL. +// +INFO_BLOCK +NdisMlidInfoBlock = { + 0xE, + { + GetMLIDConfiguration, + GetMLIDStatistics, + AddMulticastAddress, + DeleteMulticastAddress, + NULL, + MLIDShutdown, + MLIDReset, + NULL, + NULL, + SetLookAheadSize, + PromiscuousChange, + NULL, + NULL, + MLIDManagement + } +}; + +MLID_Reg +NdisMlidHandlerInfo = { + MLIDSendHandler, + &NdisMlidInfoBlock +}; + + + +UINT32 +BuildNewMulticastList( + PMLID_STRUCT Mlid, + PUINT8 AddMulticastAddr + ); + +UINT32 +BuildNewFunctionalAddr( + PMLID_STRUCT Mlid, + PUINT8 AddFunctionalAddr + ); + + +UINT32 +RemoveFromMulticastList( + PMLID_STRUCT Mlid, + PUINT8 DelMulticastAddr + ); + +UINT32 +RemoveFromFunctionalAddr( + PMLID_STRUCT Mlid, + PUINT8 DelFunctionalAddr + ); + + + + + +PMLID_ConfigTable +GetMLIDConfiguration( + UINT32 BoardNumber + ) + +/*++ + +Routine Description: + + Returns a pointer to the MLIDs configuration table for the specified logical + board. This commnand is supported by all MLIDs. A separate configuration + table is maintained by the MLID for each adapter/frame-type combination. + +Arguments: + + BoardNumber - The board number. + +Return Value: + + PMLID_ConfigTable - A pointer to tyhe MLIDs configuration table. + NULL - Reports the BAD_PARAMETER condition, MLID does not exist. + +--*/ + +{ + UINT32 i; + PMLID_ConfigTable ConfigTable; + + NdisAcquireSpinLock(&NdisMlidSpinLock); + + // + // Verify that BoardNumber is in valid range + // + + for (i =0 ; i < AllocatedMlidBoards; i++) { + + if (MlidBoards[i].BoardNumber == BoardNumber) { + + break; + + } + + } + + if (i == AllocatedMlidBoards) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(NULL); + + } + + // + // If BoardNumber is not open, fail. + // + + if (MlidBoards[i].Mlid == NULL) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(NULL); + + } + + // + // If Board is unloading - fail + // + if (MlidBoards[i].Mlid->Unloading) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(NULL); + } + + // + // return pointer to configuration table. + // + + ConfigTable = &(MlidBoards[i].Mlid->ConfigTable); + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(ConfigTable); + +} + + +PMLID_StatsTable +GetMLIDStatistics( + UINT32 BoardNumber + ) + +/*++ + +Routine Description: + + Returns a pointer to the MLIDs statistics table for the specified board. All + MLIDs support this command. The MLID maintains one statistics table for each + physical adapter. Each frame-type (or logical board) present for that physical + adapter uses the same table. The board number can be any of the logical + board values present for the physical adapter. Regardless of the logical + board number, GetMLIDStatistics will return the same table. + +Arguments: + + BoardNumber - The board number. + +Return Value: + + PMLID_Statistics - A pointer to the MLIDs Statistics Table. + + NULL - Reports the BAD_PARAMETER condition. + +--*/ + +{ + UINT32 i; + PMLID_StatsTable StatsTable; + + NdisAcquireSpinLock(&NdisMlidSpinLock); + + // + // Verify that BoardNumber is in valid range + // + + for (i =0 ; i < AllocatedMlidBoards; i++) { + + if (MlidBoards[i].BoardNumber == BoardNumber) { + + break; + + } + + } + + if (i == AllocatedMlidBoards) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(NULL); + + } + + // + // If BoardNumber is not open, fail. + // + + if (MlidBoards[i].Mlid == NULL) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(NULL); + + } + + // + // If Board is unloading - fail + // + if (MlidBoards[i].Mlid->Unloading) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(NULL); + } + + // + // return pointer to statistics table. + // + + StatsTable = &(MlidBoards[i].Mlid->StatsTable->StatsTable); + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(StatsTable); + +} + + +UINT32 +AddMulticastAddress( + UINT32 BoardNumber, + PUINT8 AddMulticastAddr + ) + +/*++ + +Routine Description: + + The MLID manages enabled multicast addresses according to the physical adapter. + The format of the multicast address is LAN medium dependent. This routine + allows a protocol to add a single multicast address. + +Arguments: + + BoardNumber - The board number. + + AddMulticastAddr - A pointer to the multicast address to add. + +Return Value: + + SUCCESSFUL - Success. + OUT_OF_RESOURCES - The MLID has insufficient resources to enable the address. + BAD_PARAMETER - The address is not valid for the MLIDs media type. + BAD_COMMAND - Multicast addressing is not supported by the MLID. + +--*/ + +{ + PMLID_STRUCT Mlid; + UINT32 i; + UINT32 Status; + NDIS_STATUS NdisStatus; + PNDIS_REQUEST NdisMlidRequest; + + NdisAcquireSpinLock(&NdisMlidSpinLock); + + // + // Verify that BoardNumber is in valid range + // + + for (i =0 ; i < AllocatedMlidBoards; i++) { + + if (MlidBoards[i].BoardNumber == BoardNumber) { + + break; + + } + + } + + if (i == AllocatedMlidBoards) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + + } + + // + // If BoardNumber is not open, fail. + // + + if (MlidBoards[i].Mlid == NULL) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + + } + + // + // If Board is unloading - fail + // + if (MlidBoards[i].Mlid->Unloading) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + } + + Mlid = MlidBoards[i].Mlid; + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + switch (Mlid->NdisMlidMedium) { + + case NdisMedium802_3: + Status = BuildNewMulticastList(Mlid, AddMulticastAddr); + break; + + case NdisMedium802_5: + Status = BuildNewFunctionalAddr(Mlid, AddMulticastAddr); + break; + + case NdisMediumFddi: + Status = BuildNewMulticastList(Mlid, AddMulticastAddr); + break; + + } + + if (Status == DUPLICATE_ENTRY) { + + // + // The address already existed, return success + // + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(SUCCESSFUL); + } + + if (Status != SUCCESSFUL) { + + // + // return error message -- most likely, OUT_OF_RESOURCES + // + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(Status); + + } + + // + // Allocate NDIS_REQUEST + // + NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST)); + + if (NdisMlidRequest == NULL) { + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(OUT_OF_RESOURCES); + + } + + // + // Build an NDIS request + // + NdisMlidRequest->RequestType = NdisRequestSetInformation; + + switch (Mlid->NdisMlidMedium) { + + case NdisMedium802_3: + NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST; + NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)(Mlid->MulticastAddresses.Addresses); + NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = + Mlid->MulticastAddresses.MACount * 6; + break; + + case NdisMedium802_5: + NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL; + NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(Mlid->MulticastAddresses.FunctionalAddr); + NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = 4; + break; + + case NdisMediumFddi: + NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST; + NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)(Mlid->MulticastAddresses.Addresses); + NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = + Mlid->MulticastAddresses.MACount * 6; + break; + + } + + NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + + Mlid->RequestStatus = NDIS_STATUS_PENDING; + + // + // Release spin lock + // + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + // + // Submit NDIS request + // + + NdisRequest( + &NdisStatus, + Mlid->NdisBindingHandle, + NdisMlidRequest + ); + + // + // If it pended, see if it completed already. + // + if (NdisStatus == NDIS_STATUS_PENDING) { + + if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) { + + // + // Assume it will complete successfully + // + NdisStatus = NDIS_STATUS_SUCCESS; + + } else { + + NdisStatus = (NDIS_STATUS)Mlid->RequestStatus; + + } + + } else { + + // + // Free NDIS_REQUEST + // + ExFreePool(NdisMlidRequest); + + } + + // + // return status + // + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + return(SUCCESSFUL); + + } + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + // + // Remove the address - error + // + + switch (Mlid->NdisMlidMedium) { + + case NdisMedium802_3: + Status = RemoveFromMulticastList(Mlid, AddMulticastAddr); + break; + + case NdisMedium802_5: + Status = RemoveFromFunctionalAddr(Mlid, AddMulticastAddr); + break; + + case NdisMediumFddi: + Status = RemoveFromMulticastList(Mlid, AddMulticastAddr); + break; + + } + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + if (NdisStatus == NDIS_STATUS_RESOURCES) { + + return(OUT_OF_RESOURCES); + + } + + return(BAD_PARAMETER); + +} + + +UINT32 +DeleteMulticastAddress( + UINT32 BoardNumber, + PUINT8 DelMulticastAddr + ) + +/*++ + +Routine Description: + + Disables the reception of a previously enabled multicast address. + +Arguments: + + BoardNumber - The board number. + + DelMulticastAddr - The address to remove/disable. + +Return Value: + + SUCCESSFUL - Success. + ITEM_NOT_PRESENT - The specified address is not enabled for the MLID. + BAD_PARAMETER - The address is not valid for the MLIDs media type. + BAD_COMMAND - Multicast addressing is not supported by the MLID. + +--*/ + +{ + PMLID_STRUCT Mlid; + UINT32 i; + UINT32 Status; + NDIS_STATUS NdisStatus; + PNDIS_REQUEST NdisMlidRequest; + + NdisAcquireSpinLock(&NdisMlidSpinLock); + + // + // Verify that BoardNumber is in valid range + // + + for (i =0 ; i < AllocatedMlidBoards; i++) { + + if (MlidBoards[i].BoardNumber == BoardNumber) { + + break; + + } + + } + + if (i == AllocatedMlidBoards) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + + } + + // + // If BoardNumber is not open, fail. + // + + if (MlidBoards[i].Mlid == NULL) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + + } + + // + // If Board is unloading - fail + // + if (MlidBoards[i].Mlid->Unloading) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + } + + Mlid = MlidBoards[i].Mlid; + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + switch (Mlid->NdisMlidMedium) { + + case NdisMedium802_3: + Status = RemoveFromMulticastList(Mlid, DelMulticastAddr); + break; + + case NdisMedium802_5: + Status = RemoveFromFunctionalAddr(Mlid, DelMulticastAddr); + break; + + case NdisMediumFddi: + Status = RemoveFromMulticastList(Mlid, DelMulticastAddr); + break; + + } + + if (Status == DUPLICATE_ENTRY) { + + // + // The address still exists, return success + // + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(SUCCESSFUL); + } + + if (Status != SUCCESSFUL) { + + // + // return error message -- most likely, ITEM_NOT_PRESENT + // + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(Status); + + } + + // + // Allocate NDIS_REQUEST + // + NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST)); + + if (NdisMlidRequest == NULL) { + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(OUT_OF_RESOURCES); + + } + + + // + // Build an NDIS request + // + NdisMlidRequest->RequestType = NdisRequestSetInformation; + + switch (Mlid->NdisMlidMedium) { + + case NdisMedium802_3: + NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST; + NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)(Mlid->MulticastAddresses.Addresses); + NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = + Mlid->MulticastAddresses.MACount * 6; + break; + + case NdisMedium802_5: + NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL; + NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(Mlid->MulticastAddresses.FunctionalAddr); + NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = 4; + break; + + case NdisMediumFddi: + NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST; + NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)(Mlid->MulticastAddresses.Addresses); + NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = + Mlid->MulticastAddresses.MACount * 6; + break; + + } + + NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + + Mlid->RequestStatus = NDIS_STATUS_PENDING; + + // + // Release spin lock + // + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + // + // Submit NDIS request + // + + NdisRequest( + &NdisStatus, + Mlid->NdisBindingHandle, + NdisMlidRequest + ); + + // + // If it pended, see if it completed already. + // + if (NdisStatus == NDIS_STATUS_PENDING) { + + if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) { + + // + // Assume it will complete successfully + // + NdisStatus = NDIS_STATUS_SUCCESS; + + } else { + + NdisStatus = (NDIS_STATUS)Mlid->RequestStatus; + + } + + } else { + + // + // Free NDIS_REQUEST + // + ExFreePool(NdisMlidRequest); + + } + + // + // return status + // + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + return(SUCCESSFUL); + + } + + // + // Put the address back -- error + // + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + switch (Mlid->NdisMlidMedium) { + + case NdisMedium802_3: + Status = BuildNewMulticastList(Mlid, DelMulticastAddr); + break; + + case NdisMedium802_5: + Status = BuildNewFunctionalAddr(Mlid, DelMulticastAddr); + break; + + case NdisMediumFddi: + Status = BuildNewMulticastList(Mlid, DelMulticastAddr); + break; + + } + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + return(BAD_PARAMETER); +} + + +UINT32 +MLIDShutdown( + UINT32 BoardNumber, + UINT32 ShutDownType + ) + +/*++ + +Routine Description: + + Allows an application to shut down a physical adapter. + +Arguments: + + BoardNumber - The board number. + + ShutDownType - Form of shutdown desired: 0 == shutdown hardware and deregister + from LSL, 0 != shutdown hardware only. + +Return Value: + + SUCCESSFUL - Success. + FAIL - Could not shutdown hardware. + BAD_COMMAND - The MLID does not support this command. + +--*/ + +{ + + // + // Always return BAD_COMMAND. First, because it is easy. Second because + // we cannot guarantee that the we know of all accesses to the NDIS MAC. + // + + return(BAD_COMMAND); + +} + + +UINT32 +MLIDReset( + UINT32 BoardNumber + ) + +/*++ + +Routine Description: + + Causes the MLID to totally re-initialize the physical adapter. Leaves any + multicast addresses that were previously enabled. + +Arguments: + + BoardNumber - The board number. + +Return Value: + + SUCCESSFUL - Success. + FAIL - The MLID was unable to reset its hardware. + BAD_COMMAND - The MLID does not support this command. + +--*/ + +{ + PMLID_STRUCT Mlid; + UINT32 i; + NDIS_STATUS NdisStatus; + + NdisAcquireSpinLock(&NdisMlidSpinLock); + + // + // Verify that BoardNumber is in valid range + // + + for (i =0 ; i < AllocatedMlidBoards; i++) { + + if (MlidBoards[i].BoardNumber == BoardNumber) { + + break; + + } + + } + + if (i == AllocatedMlidBoards) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(FAIL); + + } + + // + // If BoardNumber is not open, fail. + // + + if (MlidBoards[i].Mlid == NULL) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(FAIL); + + } + + // + // If Board is unloading - fail + // + if (MlidBoards[i].Mlid->Unloading) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(FAIL); + } + + Mlid = MlidBoards[i].Mlid; + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + // + // Hack so that we will cancel all requests until the reset completes + // + Mlid->Unloading = TRUE; + + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[12].StatCounter)))++; // MAdapterResetCount + + // + // Time stamp the sucker + // + { + LARGE_INTEGER TimeStamp; + + KeQuerySystemTime(&TimeStamp); + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[13].StatCounter))) = // MAdapterOprTimeStamp + TimeStamp.LowPart; + + } + + + // + // Release spin lock + // + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + // + // Call NdisReset + // + + NdisReset( + &NdisStatus, + Mlid->NdisBindingHandle + ); + + // + // If it pended, see if it completed already. + // + if (NdisStatus == NDIS_STATUS_PENDING) { + + if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) { + + // + // Assume it will complete successfully + // + NdisStatus = NDIS_STATUS_SUCCESS; + + } else { + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + Mlid->Unloading = FALSE; + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + NdisStatus = (NDIS_STATUS)Mlid->RequestStatus; + + } + + } else { + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + Mlid->Unloading = FALSE; + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + } + + // + // return status + // + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + return(SUCCESSFUL); + + } + + return(FAIL); + +} + + +UINT32 +SetLookAheadSize( + UINT32 BoardNumber, + UINT32 RequestSize + ) + +/*++ + +Routine Description: + + Tells the MLID the amount of look ahead data that is needed by the caller + to properly process received packets. + +Arguments: + + BoardNumber - The board number. + + RequestedSize - Requested look ahead size in bytes. + +Return Value: + + SUCCESSFUL - Success. + BAD_PARAMETER - Requested look ahead size exceed bounds. + +--*/ + +{ + PMLID_STRUCT Mlid; + UINT32 i; + UINT32 OldSize; + NDIS_STATUS NdisStatus; + PNDIS_REQUEST NdisMlidRequest; + + // + // Verify that the size is ok + // + + if (RequestSize > (256 - 40)) { // 40 is largest Media header size (TR SNAP w/ SR) + + return(BAD_PARAMETER); + + } + + RequestSize += 40; + + NdisAcquireSpinLock(&NdisMlidSpinLock); + + // + // Verify that BoardNumber is in valid range + // + + for (i =0 ; i < AllocatedMlidBoards; i++) { + + if (MlidBoards[i].BoardNumber == BoardNumber) { + + break; + + } + + } + + if (i == AllocatedMlidBoards) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + + } + + // + // If BoardNumber is not open, fail. + // + + if (MlidBoards[i].Mlid == NULL) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + + } + + // + // If Board is unloading - fail + // + if (MlidBoards[i].Mlid->Unloading) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + } + + + Mlid = MlidBoards[i].Mlid; + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + // + // Allocate NDIS_REQUEST + // + NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST)); + + if (NdisMlidRequest == NULL) { + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(OUT_OF_RESOURCES); + + } + + // + // Store lookahead size + // + OldSize = Mlid->ConfigTable.MLIDCFG_LookAheadSize; + Mlid->ConfigTable.MLIDCFG_LookAheadSize = RequestSize; + + + // + // Build an NDIS request + // + NdisMlidRequest->RequestType = NdisRequestSetInformation; + + NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_GEN_MAXIMUM_LOOKAHEAD; + NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(Mlid->ConfigTable.MLIDCFG_LookAheadSize); + NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = sizeof(UINT32); + + NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + + Mlid->RequestStatus = NDIS_STATUS_PENDING; + + // + // Release spin lock + // + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + // + // Submit NDIS request + // + + NdisRequest( + &NdisStatus, + Mlid->NdisBindingHandle, + NdisMlidRequest + ); + + // + // If it pended, see if it completed already. + // + if (NdisStatus == NDIS_STATUS_PENDING) { + + if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) { + + // + // Assume it will complete successfully + // + NdisStatus = NDIS_STATUS_SUCCESS; + + } else { + + NdisStatus = (NDIS_STATUS)Mlid->RequestStatus; + + } + + } else { + + // + // Free NDIS_REQUEST + // + ExFreePool(NdisMlidRequest); + + } + + // + // return status + // + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + return(SUCCESSFUL); + + } + + // + // Restore old size + // + Mlid->ConfigTable.MLIDCFG_LookAheadSize = OldSize; + + return(BAD_PARAMETER); + +} + + +UINT32 +PromiscuousChange( + UINT32 BoardNumber, + UINT32 PromiscuousState, + UINT32 PromiscuousMode + ) + +/*++ + +Routine Description: + + Used to enable and disable promiscuous mode on the MLIDs adapter. A protocol + stack can enable promiscuous mode multiple times without error; however, only + the current call is in effect. If the LAN medium or adapter doees not distinquish + between MAC and non-MAC frames, both frames are assumed for the PromiscuousMode + mask. + + The MLID keeps a counter for each promiscuous mode and disables only when the + count reaches zero. + +Arguments: + + BoardNumber - The board number. + + PromiscuousState - If 0, then disables promiscuous mode, else enables promiscuous mode. + + PromiscuousMode - Has the mask for what type of frames the MLID is to + promiscuously receive. 0x1 - MAC Frames, 0x2 - Non-MAC Frames, 0x3 - Both. + +Return Value: + + SUCCESSFUL - Success. + BAD_COMMAND - Promiscuous mode is not supported by the MLID. + +--*/ + +{ + PMLID_STRUCT Mlid; + UINT32 i; + UINT32 OldFilterValue; + UINT32 OldCount; + NDIS_STATUS NdisStatus; + PNDIS_REQUEST NdisMlidRequest; + + NdisAcquireSpinLock(&NdisMlidSpinLock); + + // + // Verify that BoardNumber is in valid range + // + + for (i =0 ; i < AllocatedMlidBoards; i++) { + + if (MlidBoards[i].BoardNumber == BoardNumber) { + + break; + + } + + } + + if (i == AllocatedMlidBoards) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + + } + + // + // If BoardNumber is not open, fail. + // + + if (MlidBoards[i].Mlid == NULL) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + + } + + // + // If Board is unloading - fail + // + if (MlidBoards[i].Mlid->Unloading) { + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + return(BAD_PARAMETER); + } + + Mlid = MlidBoards[i].Mlid; + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + // + // If already enabled and we are to enable it, then increment counter and exit + // + if ((PromiscuousState != 0) && + (Mlid->PromiscuousModeEnables != 0)) { + + Mlid->PromiscuousModeEnables++; + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(SUCCESSFUL); + + } + + // + // If we are to disable it and count > 1 then decrement counter and exit + // + if ((PromiscuousState == 0) && + (Mlid->PromiscuousModeEnables > 1)) { + + Mlid->PromiscuousModeEnables--; + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(SUCCESSFUL); + + } + + // + // Allocate NDIS_REQUEST + // + NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST)); + + if (NdisMlidRequest == NULL) { + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + return(OUT_OF_RESOURCES); + + } + + // + // Save old value + // + OldFilterValue = Mlid->NdisPacketFilterValue; + OldCount = Mlid->PromiscuousModeEnables; + + if (PromiscuousState == 0) { + + Mlid->PromiscuousModeEnables = 0; + Mlid->NdisPacketFilterValue &= ~(NDIS_PACKET_TYPE_PROMISCUOUS); + + } else { + + Mlid->PromiscuousModeEnables = 1; + Mlid->NdisPacketFilterValue |= NDIS_PACKET_TYPE_PROMISCUOUS; + + } + + // + // Build an NDIS request + // + NdisMlidRequest->RequestType = NdisRequestSetInformation; + + NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER; + NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(Mlid->NdisPacketFilterValue); + NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = sizeof(UINT32); + + NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + + Mlid->RequestStatus = NDIS_STATUS_PENDING; + + // + // Release spin lock + // + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + // + // Submit NDIS request + // + + NdisRequest( + &NdisStatus, + Mlid->NdisBindingHandle, + NdisMlidRequest + ); + + // + // If it pended, see if it completed already. + // + if (NdisStatus == NDIS_STATUS_PENDING) { + + if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) { + + // + // Assume it will complete successfully + // + NdisStatus = NDIS_STATUS_SUCCESS; + + } else { + + NdisStatus = (NDIS_STATUS)Mlid->RequestStatus; + + } + + } else { + + // + // Free NDIS_REQUEST + // + ExFreePool(NdisMlidRequest); + + } + + // + // return status + // + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + return(SUCCESSFUL); + + } + + // + // restore state + // + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + Mlid->NdisPacketFilterValue = OldFilterValue; + Mlid->PromiscuousModeEnables = OldCount; + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + + return(BAD_COMMAND); + +} + + +UINT32 +MLIDManagement( + UINT32 BoardNumber, + PECB ManagementECB + ) + +/*++ + +Routine Description: + + Allows a management entity to access management information from/and control + an MLID. + +Arguments: + + BoardNumber - The board number. + + ManagementECB - A pointer to an ECB containing the management information. + +Return Value: + + SUCCESSFUL - Success. + RESPONSE_DELAYED - Command will complete asyncronously. + BAD_COMMAND - Not supported. + BAD_PARAMETER - The Protocol ID field is invalid. + NO_SUCH_HANDLER - Management entity for the Management Handle in teh ECB does + not exist + +--*/ + +{ + + // + // Always return BAD_COMMAND. + // + + return(BAD_COMMAND); + +} + + +VOID +MLIDSendHandler( + PECB SendECB + ) + +/*++ + +Routine Description: + + This routine takes an ECB, assembles a packet based on the frame-type and + sends it on the wire. + +Arguments: + + SendECB - A pointer to the ECB discribing the data and destination address for + the packet. + +Return Value: + + None. + +--*/ + +{ + PMLID_STRUCT Mlid; + UINT32 i; + BOOLEAN Result; + + NdisAcquireSpinLock(&NdisMlidSpinLock); + + // + // Verify that BoardNumber is in valid range + // + + for (i =0 ; i < AllocatedMlidBoards; i++) { + + if (MlidBoards[i].BoardNumber == SendECB->ECB_BoardNumber) { + + break; + + } + + } + + if (i == AllocatedMlidBoards) { + + // + // Cancel the ECB + // + + SendECB->ECB_Status = (UINT16)CANCELED; + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + // + // We could try to find a board number with a link to the LSL, but + // in any case we might fail. The transport and/or LSL has hosed us, + // so we will just let it sit. + // + return; + + } + + // + // If BoardNumber is not open, fail. + // + + if (MlidBoards[i].Mlid == NULL) { + + + // + // Cancel the ECB + // + + SendECB->ECB_Status = (UINT16)CANCELED; + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + // + // We could try to find a board number with a link to the LSL, but + // in any case we might fail. The transport and/or LSL has hosed us, + // so we will just let it sit. + // + return; + + } + + // + // If Board is unloading - fail + // + if (MlidBoards[i].Mlid->Unloading) { + + + // + // Cancel the ECB + // + + SendECB->ECB_Status = (UINT16)CANCELED; + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + // + // We could try to find a board number with a link to the LSL, but + // in any case we might fail. The transport and/or LSL has hosed us, + // so we will just let it sit. + // + return; + } + + Mlid = MlidBoards[i].Mlid; + + NdisAcquireSpinLock(&(Mlid->MlidSpinLock)); + + NdisReleaseSpinLock(&NdisMlidSpinLock); + + // + // Update MTotalGroupAddrTxCount + // + switch (Mlid->NdisMlidMedium) { + + case NdisMediumFddi: + case NdisMedium802_3: + + if (ETH_IS_BROADCAST(SendECB->ECB_ImmediateAddress)) { + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++; + break; + } + + if (ETH_IS_MULTICAST(SendECB->ECB_ImmediateAddress)) { + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++; + break; + } + + if (ETH_IS_MULTICAST(SendECB->ECB_ImmediateAddress)) { + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++; + break; + } + break; + + case NdisMedium802_5: + + TR_IS_BROADCAST(SendECB->ECB_ImmediateAddress, &Result); + if (Result == TRUE) { + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++; + break; + } + + TR_IS_GROUP(SendECB->ECB_ImmediateAddress, &Result); + if (Result == TRUE) { + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++; + break; + } + + TR_IS_FUNCTIONAL(SendECB->ECB_ImmediateAddress, &Result); + if (Result == TRUE) { + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++; + break; + } + break; + + } + + (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[14].StatCounter)))++; // MQDepth + + // + // Put ECB on send queue + // + + if (Mlid->FirstPendingSend == NULL) { + + Mlid->FirstPendingSend = SendECB; + Mlid->LastPendingSend = SendECB; + SendECB->ECB_NextLink = NULL; + SendECB->ECB_PreviousLink = NULL; + + } else { + + Mlid->LastPendingSend->ECB_NextLink = SendECB; + SendECB->ECB_PreviousLink = Mlid->LastPendingSend; + SendECB->ECB_NextLink = NULL; + Mlid->LastPendingSend = SendECB; + + } + + // + // Send all packets possible + // + + if (Mlid->StageOpen && !Mlid->InSendPacket) { + + SendPackets(Mlid); + + } + + NdisReleaseSpinLock(&(Mlid->MlidSpinLock)); + +} + + +UINT32 +BuildNewMulticastList( + PMLID_STRUCT Mlid, + PUINT8 AddMulticastAddr + ) + +/*++ + +Routine Description: + + This routine takes a multicast addresses for either Ethernet or FDDI and + adds it to the Mlids database if it does not exist, otherwise it increments + the reference count on the address if it does exist. + +Arguments: + + Mlid - Pointer to the MLID. + + AddMulticastAddr - The multicast address to add. + +Return Value: + + SUCCESSFUL - Success. + DUPLICATE_ENTRY - The address already existed in the database. + OUT_OF_RESOURCES - No memory avaiable to grow database. + +--*/ + +{ + UINT32 i; + + // + // If address already exists, increment counter. + // + for (i = 0; i < Mlid->MulticastAddresses.MACount; i++) { + + if (RtlCompareMemory(Mlid->MulticastAddresses.Addresses + i * 6, + AddMulticastAddr, + 6 + ) == 0) { + + // + // Increment count and exit + // + + Mlid->MulticastAddresses.EnableCounts[i]++; + return(DUPLICATE_ENTRY); + + } + + } + + // + // Allocate space for new array, if necessary + // + if (Mlid->MulticastAddresses.MACount == Mlid->MulticastAddresses.MAAllocated) { + + PUINT8 TmpAddressArray; + PUINT32 TmpCountArray; + + // + // Allocate memory for new array + // + + TmpAddressArray = (PUINT8)ExAllocatePool(NonPagedPool, + 6 * (Mlid->MulticastAddresses.MACount + 2) + ); + + if (TmpAddressArray == NULL) { + + return(OUT_OF_RESOURCES); + + } + + TmpCountArray = (PUINT32)ExAllocatePool(NonPagedPool, + sizeof(UINT32) * + (Mlid->MulticastAddresses.MACount + 2) + ); + + if (TmpCountArray == NULL) { + + return(OUT_OF_RESOURCES); + + } + + // + // Copy over old addresses + // + RtlCopyMemory(TmpAddressArray, + Mlid->MulticastAddresses.Addresses, + 6 * Mlid->MulticastAddresses.MACount + ); + + // + // Copy over old counts + // + RtlCopyMemory(TmpCountArray, + Mlid->MulticastAddresses.EnableCounts, + sizeof(UINT32) * Mlid->MulticastAddresses.MACount + ); + + // + // Free old resources + // + ExFreePool(Mlid->MulticastAddresses.Addresses); + ExFreePool(Mlid->MulticastAddresses.EnableCounts); + + // + // Save new space + // + Mlid->MulticastAddresses.Addresses = TmpAddressArray; + Mlid->MulticastAddresses.EnableCounts = TmpCountArray; + + // + // Increment allocated count + // + Mlid->MulticastAddresses.MAAllocated += 2; + + } + + // + // Put address in new slot + // + RtlCopyMemory(Mlid->MulticastAddresses.Addresses + + Mlid->MulticastAddresses.MACount * 6, + AddMulticastAddr, + 6 + ); + + // + // Set reference count + // + Mlid->MulticastAddresses.EnableCounts[Mlid->MulticastAddresses.MACount] = 1; + + Mlid->MulticastAddresses.MACount++; + + return(SUCCESSFUL); + +} + + +UINT32 +BuildNewFunctionalAddr( + PMLID_STRUCT Mlid, + PUINT8 AddFunctionalAddr + ) + +/*++ + +Routine Description: + + This routine takes a functional address(es) for token ring and + adds it to the Mlid functional address if it does not exist, otherwise + it increments the reference count on the address(es) if it does exist. + +Arguments: + + Mlid - Pointer to the MLID. + + AddFunctionalAddr - The functional address to add. + +Return Value: + + SUCCESSFUL - Success. + DUPLICATE_ENTRY - The address already existed in the database. + OUT_OF_RESOURCES - No memory avaiable to grow database. + +--*/ + +{ + UINT32 i; + UINT32 ShortenedFunctionalAddr; + UNALIGNED UINT32 *PAddr; + UINT32 NewAddressBits; + UINT32 OldAddressBits; + + if (Mlid->MulticastAddresses.MAAllocated == 0) { + + // + // Get memory for the counts + // + + Mlid->MulticastAddresses.EnableCounts = (PUINT32)ExAllocatePool(NonPagedPool, + sizeof(UINT32) * 32 + ); + + if (Mlid->MulticastAddresses.EnableCounts == NULL) { + + return(OUT_OF_RESOURCES); + + } + + RtlZeroMemory(Mlid->MulticastAddresses.EnableCounts, sizeof(UINT32) * 32); + + Mlid->MulticastAddresses.MAAllocated = 32; + + } + + // + // Get low four bytes of address + // + PAddr = (UNALIGNED UINT32 *)(AddFunctionalAddr + 2); + ShortenedFunctionalAddr = *PAddr; + + // + // Get new bits and old bits + // + OldAddressBits = Mlid->MulticastAddresses.FunctionalAddr & ShortenedFunctionalAddr; + NewAddressBits = ShortenedFunctionalAddr ^ OldAddressBits; + + // + // Increment count of each bit that exists in current functional address + // + i = 0; + + while (OldAddressBits != 0) { + + if (OldAddressBits & 1) { + + Mlid->MulticastAddresses.EnableCounts[i]++; + + } + + OldAddressBits >>= 1; + i++; + + } + + if (NewAddressBits == 0) { + + return(DUPLICATE_ENTRY); + + } + + // + // Store new bits + // + + Mlid->MulticastAddresses.FunctionalAddr |= NewAddressBits; + + // + // Set counts of each new address bit + // + + i = 0; + + while (NewAddressBits != 0) { + + if (NewAddressBits & 1) { + + Mlid->MulticastAddresses.EnableCounts[i] = 1; + + } + + NewAddressBits >>= 1; + i++; + + } + + return(SUCCESSFUL); + +} + + +UINT32 +RemoveFromMulticastList( + PMLID_STRUCT Mlid, + PUINT8 DelMulticastAddr + ) + +/*++ + +Routine Description: + + This routine takes a multicast addresses for either Ethernet or FDDI and + removes it from the Mlids database if the reference count is one, otherwise + it decrements the reference count on the address. + +Arguments: + + Mlid - Pointer to the MLID. + + DelMulticastAddr - The multicast address to add. + +Return Value: + + SUCCESSFUL - Success and address is removed. + ITEM_NOT_PRESENT - The address does not exist in the database. + DUPLICATE_ENTRY - Success and address still exists. + +--*/ + +{ + UINT32 i; + + // + // If address already exists, decrement counter. + // + for (i = 0; i < Mlid->MulticastAddresses.MACount; i++) { + + if (RtlCompareMemory(Mlid->MulticastAddresses.Addresses + i * 6, + DelMulticastAddr, + 6 + ) == 0) { + + // + // Increment count and exit + // + + Mlid->MulticastAddresses.EnableCounts[i]--; + + // + // If this is not the last reference we can exit now + // + if (Mlid->MulticastAddresses.EnableCounts[i] != 0) { + + return(DUPLICATE_ENTRY); + + } + + // + // Now we need to adjust the address array and counts array + // + + RtlMoveMemory( + Mlid->MulticastAddresses.Addresses + i * 6, + Mlid->MulticastAddresses.Addresses + (i + 1) * 6, + 6 * (Mlid->MulticastAddresses.MACount - (i + 1)) + ); + + RtlMoveMemory( + Mlid->MulticastAddresses.EnableCounts + i, + Mlid->MulticastAddresses.EnableCounts + (i + 1), + sizeof(UINT32) * (Mlid->MulticastAddresses.MACount - (i + 1)) + ); + + Mlid->MulticastAddresses.MACount--; + + return(SUCCESSFUL); + + } + + } + + return(ITEM_NOT_PRESENT); + +} + + +UINT32 +RemoveFromFunctionalAddr( + PMLID_STRUCT Mlid, + PUINT8 DelFunctionalAddr + ) + +/*++ + +Routine Description: + + This routine takes functional address(es) for token ring and + removes it/them from the Mlids database if the reference count i/ares one, + otherwise it decrements the reference count on the address(es). + +Arguments: + + Mlid - Pointer to the MLID. + + DelFunctionalAddr - The functional address to remove. + +Return Value: + + SUCCESSFUL - Success and address is changed. + ITEM_NOT_PRESENT - The address does not exist in the database. + DUPLICATE_ENTRY - Success and address is unchanged. + +--*/ + +{ + UINT32 i; + UINT32 ShortenedFunctionalAddr; + UNALIGNED UINT32 *PAddr; + UINT32 OldAddressBits; + UINT32 Status = DUPLICATE_ENTRY; + + if (Mlid->MulticastAddresses.MAAllocated == 0) { + + return(ITEM_NOT_PRESENT); + + } + + // + // Get low four bytes of address + // + PAddr = (UNALIGNED UINT32 *)(DelFunctionalAddr + 2); + ShortenedFunctionalAddr = *PAddr; + + // + // Get new bits and old bits + // + OldAddressBits = Mlid->MulticastAddresses.FunctionalAddr & ShortenedFunctionalAddr; + + if (OldAddressBits != ShortenedFunctionalAddr) { + + return(ITEM_NOT_PRESENT); + + } + + // + // Increment count of each bit that exists in current functional address + // + i = 0; + + while (OldAddressBits != 0) { + + if (OldAddressBits & 1) { + + Mlid->MulticastAddresses.EnableCounts[i]--; + + if (Mlid->MulticastAddresses.EnableCounts[i] == 0) { + + // + // Remove this bit + // + + Mlid->MulticastAddresses.FunctionalAddr &= ~(1 << i); + + Status = SUCCESSFUL; + + } + + } + + OldAddressBits >>= 1; + i++; + + } + + return(Status); + +} + |