summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/lsl/lslmlid.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/lsl/lslmlid.c2085
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);
+
+}
+