679 lines
21 KiB
C
679 lines
21 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
llcinfo.c
|
||
|
||
Abstract:
|
||
|
||
Includes set/get information primitives of the data link driver.
|
||
|
||
Contents:
|
||
LlcQueryInformation
|
||
LlcSetInformation
|
||
UpdateFunctionalAddress
|
||
UpdateGroupAddress
|
||
|
||
Author:
|
||
|
||
Antti Saarenheimo (o-anttis) 17-MAY-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <llc.h>
|
||
|
||
//
|
||
// We are using only a single state state machine defined
|
||
// in IBM Token-Ring Architecture. On the other hand, DLC
|
||
// API requires a state machine having primary and secondary
|
||
// states. The secondary states are used only when the link is
|
||
// open. These tables converts the single internal state to
|
||
// the primary and secondary states.
|
||
//
|
||
|
||
UCHAR PrimaryStates[MAX_LLC_LINK_STATE] = {
|
||
LLC_LINK_CLOSED, // LINK_CLOSED,
|
||
LLC_DISCONNECTED, // DISCONNECTED,
|
||
LLC_LINK_OPENING, // LINK_OPENING,
|
||
LLC_DISCONNECTING, // DISCONNECTING,
|
||
LLC_FRMR_SENT, // FRMR_SENT,
|
||
LLC_LINK_OPENED, // LINK_OPENED,
|
||
LLC_LINK_OPENED, // LOCAL_BUSY,
|
||
LLC_LINK_OPENED, // REJECTION
|
||
LLC_LINK_OPENED, // CHECKPOINTING
|
||
LLC_LINK_OPENED, // CHKP_LOCAL_BUSY
|
||
LLC_LINK_OPENED, // CHKP_REJECT
|
||
LLC_RESETTING, // RESETTING
|
||
LLC_LINK_OPENED, // REMOTE_BUSY
|
||
LLC_LINK_OPENED, // LOCAL_REMOTE_BUSY
|
||
LLC_LINK_OPENED, // REJECT_LOCAL_BUSY
|
||
LLC_LINK_OPENED, // REJECT_REMOTE_BUSY
|
||
LLC_LINK_OPENED, // CHKP_REJECT_LOCAL_BUSY
|
||
LLC_LINK_OPENED, // CHKP_CLEARING
|
||
LLC_LINK_OPENED, // CHKP_REJECT_CLEARING
|
||
LLC_LINK_OPENED, // REJECT_LOCAL_REMOTE_BUSY
|
||
LLC_FRMR_RECEIVED // FRMR_RECEIVED
|
||
};
|
||
|
||
//
|
||
// Note: the local busy state must be set separately!
|
||
//
|
||
|
||
UCHAR SecondaryStates[MAX_LLC_LINK_STATE] = {
|
||
LLC_NO_SECONDARY_STATE, // LINK_CLOSED,
|
||
LLC_NO_SECONDARY_STATE, // DISCONNECTED,
|
||
LLC_NO_SECONDARY_STATE, // LINK_OPENING,
|
||
LLC_NO_SECONDARY_STATE, // DISCONNECTING,
|
||
LLC_NO_SECONDARY_STATE, // FRMR_SENT,
|
||
LLC_NO_SECONDARY_STATE, // LINK_OPENED,
|
||
LLC_NO_SECONDARY_STATE, // LOCAL_BUSY,
|
||
LLC_REJECTING, // REJECTION
|
||
LLC_CHECKPOINTING, // CHECKPOINTING
|
||
LLC_CHECKPOINTING, // CHKP_LOCAL_BUSY
|
||
LLC_CHECKPOINTING|LLC_REJECTING, // CHKP_REJECT
|
||
LLC_NO_SECONDARY_STATE, // RESETTING
|
||
LLC_REMOTE_BUSY, // REMOTE_BUSY
|
||
LLC_REMOTE_BUSY, // LOCAL_REMOTE_BUSY
|
||
LLC_REJECTING, // REJECT_LOCAL_BUSY
|
||
LLC_REJECTING|LLC_REMOTE_BUSY, // REJECT_REMOTE_BUSY
|
||
LLC_CHECKPOINTING|LLC_REJECTING, // CHKP_REJECT_LOCAL_BUSY
|
||
LLC_CHECKPOINTING|LLC_CLEARING, // CHKP_CLEARING
|
||
LLC_CHECKPOINTING|LLC_CLEARING|LLC_REJECTING, // CHKP_REJECT_CLEARING
|
||
LLC_REJECTING|LLC_REMOTE_BUSY, // REJECT_LOCAL_REMOTE_BUSY
|
||
LLC_NO_SECONDARY_STATE // FRMR_RECEIVED
|
||
};
|
||
|
||
|
||
DLC_STATUS
|
||
LlcQueryInformation(
|
||
IN PVOID hObject,
|
||
IN UINT InformationType,
|
||
IN PLLC_QUERY_INFO_BUFFER pQuery,
|
||
IN UINT QueryBufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Procedure returns the statistics or parameter information of
|
||
the given LLC object.
|
||
|
||
Arguments:
|
||
|
||
hObject - LLC object
|
||
InformationType - the requested information (NDIS, Statistics, params)
|
||
pQuery - buffer for the queried parameters
|
||
QueryBufferSize - size of the buffer
|
||
|
||
Return Value:
|
||
|
||
DLC_STATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID CopyBuffer = NULL; // no warnings when -W4
|
||
UINT CopyLength = 0; // no warnings when -W4
|
||
DLC_STATUS Status = STATUS_SUCCESS;
|
||
PADAPTER_CONTEXT pAdapterContext;
|
||
|
||
switch (InformationType) {
|
||
case DLC_INFO_CLASS_STATISTICS:
|
||
case DLC_INFO_CLASS_STATISTICS_RESET:
|
||
switch (((PDATA_LINK)hObject)->Gen.ObjectType) {
|
||
case LLC_DIRECT_OBJECT:
|
||
|
||
//
|
||
// We don't gather any staticstics for direct objects
|
||
//
|
||
|
||
CopyBuffer = &(((PLLC_STATION_OBJECT)hObject)->Statistics);
|
||
CopyLength = sizeof(SAP_STATISTICS);
|
||
break;
|
||
|
||
case LLC_SAP_OBJECT:
|
||
|
||
//
|
||
// copy the SAP statistics, reset the old data if necessary.
|
||
// We don't check the buffer, the upper part if responsible
|
||
// of that.
|
||
//
|
||
|
||
CopyBuffer = &(((PLLC_SAP)hObject)->Statistics);
|
||
CopyLength = sizeof(SAP_STATISTICS);
|
||
break;
|
||
|
||
case LLC_LINK_OBJECT:
|
||
CopyBuffer = &(((PDATA_LINK)hObject)->Statistics);
|
||
CopyLength = sizeof(LINK_STATION_STATISTICS);
|
||
break;
|
||
|
||
#if LLC_DBG
|
||
default:
|
||
LlcInvalidObjectType();
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// Check the size of the receive buffers
|
||
//
|
||
|
||
if (CopyLength <= QueryBufferSize) {
|
||
LlcMemCpy(pQuery->auchBuffer, CopyBuffer, CopyLength);
|
||
|
||
//
|
||
// Copy also the specific link station information
|
||
//
|
||
|
||
if (((PDATA_LINK)hObject)->Gen.ObjectType == LLC_LINK_OBJECT) {
|
||
pQuery->LinkLog.uchLastCmdRespReceived = ((PDATA_LINK)hObject)->LastCmdOrRespReceived;
|
||
pQuery->LinkLog.uchLastCmdRespTransmitted = ((PDATA_LINK)hObject)->LastCmdOrRespSent;
|
||
pQuery->LinkLog.uchPrimaryState = PrimaryStates[((PDATA_LINK)hObject)->State];
|
||
pQuery->LinkLog.uchSecondaryState = SecondaryStates[((PDATA_LINK)hObject)->State];
|
||
|
||
//
|
||
// We keep a separate state by whom the local
|
||
// busy state has been set.
|
||
//
|
||
|
||
if (((PDATA_LINK)hObject)->Flags & DLC_LOCAL_BUSY_USER) {
|
||
pQuery->LinkLog.uchSecondaryState |= LLC_LOCAL_BUSY_USER_SET;
|
||
}
|
||
if (((PDATA_LINK)hObject)->Flags & DLC_LOCAL_BUSY_BUFFER) {
|
||
pQuery->LinkLog.uchSecondaryState |= LLC_LOCAL_BUSY_BUFFER_SET;
|
||
}
|
||
pQuery->LinkLog.uchSendStateVariable = ((PDATA_LINK)hObject)->Vs / (UCHAR)2;
|
||
pQuery->LinkLog.uchReceiveStateVariable = ((PDATA_LINK)hObject)->Vr / (UCHAR)2;
|
||
pQuery->LinkLog.uchLastNr = (UCHAR)(((PDATA_LINK)hObject)->Nr / 2);
|
||
|
||
//
|
||
// The lan header used by the link is in the same
|
||
// format as the received lan headers
|
||
//
|
||
|
||
pQuery->LinkLog.cbLanHeader = (UCHAR)LlcCopyReceivedLanHeader(
|
||
((PLLC_STATION_OBJECT)hObject)->Gen.pLlcBinding,
|
||
pQuery->LinkLog.auchLanHeader,
|
||
((PDATA_LINK)hObject)->auchLanHeader
|
||
);
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// The data will be lost, when it is reset
|
||
//
|
||
|
||
Status = DLC_STATUS_LOST_LOG_DATA;
|
||
CopyLength = QueryBufferSize;
|
||
}
|
||
if (InformationType == DLC_INFO_CLASS_STATISTICS_RESET) {
|
||
LlcZeroMem(CopyBuffer, CopyLength);
|
||
}
|
||
break;
|
||
|
||
case DLC_INFO_CLASS_DLC_TIMERS:
|
||
if (QueryBufferSize < sizeof( LLC_TICKS)) {
|
||
|
||
//
|
||
// This is a wrong error message, but there is no better one
|
||
//
|
||
|
||
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
||
}
|
||
LlcMemCpy(&pQuery->Timer,
|
||
&((PBINDING_CONTEXT)hObject)->pAdapterContext->ConfigInfo.TimerTicks,
|
||
sizeof(LLC_TICKS)
|
||
);
|
||
break;
|
||
|
||
case DLC_INFO_CLASS_DIR_ADAPTER:
|
||
if (QueryBufferSize < sizeof(LLC_ADAPTER_INFO)) {
|
||
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
||
}
|
||
|
||
pAdapterContext = ((PBINDING_CONTEXT)hObject)->pAdapterContext;
|
||
SwapMemCpy(((PBINDING_CONTEXT)hObject)->SwapCopiedLanAddresses,
|
||
pQuery->Adapter.auchFunctionalAddress,
|
||
((PBINDING_CONTEXT)hObject)->Functional.auchAddress,
|
||
4
|
||
);
|
||
SwapMemCpy(((PBINDING_CONTEXT)hObject)->SwapCopiedLanAddresses,
|
||
pQuery->Adapter.auchGroupAddress,
|
||
(PUCHAR)&((PBINDING_CONTEXT)hObject)->ulBroadcastAddress,
|
||
4
|
||
);
|
||
SwapMemCpy(((PBINDING_CONTEXT)hObject)->SwapCopiedLanAddresses,
|
||
pQuery->Adapter.auchNodeAddress,
|
||
pAdapterContext->Adapter.Node.auchAddress,
|
||
6
|
||
);
|
||
pQuery->Adapter.usMaxFrameSize = (USHORT)pAdapterContext->MaxFrameSize;
|
||
pQuery->Adapter.ulLinkSpeed = pAdapterContext->LinkSpeed;
|
||
|
||
if (pAdapterContext->NdisMedium == NdisMedium802_3) {
|
||
pQuery->Adapter.usAdapterType = 0x0100; // Ethernet type in OS/2
|
||
} else if (pAdapterContext->NdisMedium == NdisMediumFddi) {
|
||
|
||
//
|
||
// NOTE: Using a currently free value to indicate FDDI
|
||
//
|
||
|
||
pQuery->Adapter.usAdapterType = 0x0200;
|
||
} else {
|
||
|
||
//
|
||
// All token-ring adapters use type "IBM tr 16/4 Adapter A",
|
||
//
|
||
|
||
pQuery->Adapter.usAdapterType = 0x0040;
|
||
}
|
||
break;
|
||
|
||
case DLC_INFO_CLASS_PERMANENT_ADDRESS:
|
||
SwapMemCpy(((PBINDING_CONTEXT)hObject)->SwapCopiedLanAddresses,
|
||
pQuery->PermanentAddress,
|
||
((PBINDING_CONTEXT)hObject)->pAdapterContext->PermanentAddress,
|
||
6
|
||
);
|
||
break;
|
||
|
||
default:
|
||
return DLC_STATUS_INVALID_COMMAND;
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
|
||
DLC_STATUS
|
||
LlcSetInformation(
|
||
IN PVOID hObject,
|
||
IN UINT InformationType,
|
||
IN PLLC_SET_INFO_BUFFER pSetInfo,
|
||
IN UINT ParameterBufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Procedure sets different parameter sets to the link station objects.
|
||
|
||
Arguments:
|
||
|
||
hObject - LLC object
|
||
InformationType - the requested information (NDIS, Statistics, params)
|
||
ParameterBuffer - buffer for the queried parameters
|
||
ParameterBufferSize - size of the buffer
|
||
|
||
Special:
|
||
|
||
Must be called IRQL < DPC (at least when broadcast addresses
|
||
are modifiled)
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
DLC_STATUS Status = STATUS_SUCCESS;
|
||
TR_BROADCAST_ADDRESS TempFunctional;
|
||
|
||
//
|
||
// There is only one high level functions, but InformationType
|
||
// and the destination station type defines the actual changed
|
||
// information.
|
||
//
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
switch (InformationType) {
|
||
case DLC_INFO_CLASS_LINK_STATION:
|
||
switch (((PDATA_LINK)hObject)->Gen.ObjectType) {
|
||
case LLC_LINK_OBJECT:
|
||
if (ParameterBufferSize < sizeof(DLC_LINK_PARAMETERS)) {
|
||
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
||
}
|
||
Status = CheckLinkParameters(&pSetInfo->LinkParms);
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
return Status;
|
||
}
|
||
|
||
ACQUIRE_SPIN_LOCK(&(((PLLC_GENERIC_OBJECT)hObject)->pAdapterContext->SendSpinLock));
|
||
|
||
SetLinkParameters((PDATA_LINK)hObject, pSetInfo->auchBuffer);
|
||
|
||
RELEASE_SPIN_LOCK(&(((PLLC_GENERIC_OBJECT)hObject)->pAdapterContext->SendSpinLock));
|
||
|
||
break;
|
||
|
||
case LLC_SAP_OBJECT:
|
||
if (ParameterBufferSize < sizeof(DLC_LINK_PARAMETERS)) {
|
||
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
||
}
|
||
Status = CheckLinkParameters(&pSetInfo->LinkParms);
|
||
if (Status != STATUS_SUCCESS) {
|
||
return Status;
|
||
}
|
||
CopyLinkParameters((PUCHAR)&((PLLC_SAP)hObject)->DefaultParameters,
|
||
(PUCHAR)&pSetInfo->LinkParms,
|
||
(PUCHAR)&DefaultParameters
|
||
);
|
||
break;
|
||
|
||
default:
|
||
return DLC_STATUS_INVALID_STATION_ID;
|
||
}
|
||
break;
|
||
|
||
case DLC_INFO_CLASS_DLC_TIMERS:
|
||
if (ParameterBufferSize < sizeof(LLC_TICKS)) {
|
||
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
||
}
|
||
|
||
//
|
||
// We will copy all non-zero timer tick values from the
|
||
// the given buffer.
|
||
//
|
||
|
||
CopyNonZeroBytes((PUCHAR)&((PBINDING_CONTEXT)hObject)->pAdapterContext->ConfigInfo.TimerTicks,
|
||
(PUCHAR)&pSetInfo->Timers,
|
||
(PUCHAR)&((PBINDING_CONTEXT)hObject)->pAdapterContext->ConfigInfo.TimerTicks,
|
||
sizeof(LLC_TICKS)
|
||
);
|
||
break;
|
||
|
||
case DLC_INFO_CLASS_SET_GROUP:
|
||
SwapMemCpy(((PBINDING_CONTEXT)hObject)->SwapCopiedLanAddresses,
|
||
(PUCHAR)&((PBINDING_CONTEXT)hObject)->ulBroadcastAddress,
|
||
pSetInfo->auchGroupAddress,
|
||
sizeof(TR_BROADCAST_ADDRESS)
|
||
);
|
||
|
||
Status = UpdateGroupAddress(((PBINDING_CONTEXT)hObject)->pAdapterContext,
|
||
(PBINDING_CONTEXT)hObject
|
||
);
|
||
break;
|
||
|
||
case DLC_INFO_CLASS_RESET_FUNCTIONAL:
|
||
case DLC_INFO_CLASS_SET_FUNCTIONAL:
|
||
SwapMemCpy(((PBINDING_CONTEXT)hObject)->SwapCopiedLanAddresses,
|
||
TempFunctional.auchAddress,
|
||
pSetInfo->auchFunctionalAddress,
|
||
sizeof(TR_BROADCAST_ADDRESS)
|
||
);
|
||
|
||
//
|
||
// We have now swapped the bits to ethernet format,
|
||
// Highest bit is now 0x01... and lowest ones are ..30,
|
||
// Reset the bits if highest (0x01) is set and set
|
||
// them if it is zero, but do not hange yje orginal
|
||
// bits: 31,1,0 that are now mapped to ethernet format.
|
||
//
|
||
|
||
if (InformationType == DLC_INFO_CLASS_SET_FUNCTIONAL) {
|
||
((PBINDING_CONTEXT)hObject)->Functional.ulAddress |= TempFunctional.ulAddress;
|
||
} else {
|
||
((PBINDING_CONTEXT)hObject)->Functional.ulAddress &= ~TempFunctional.ulAddress;
|
||
}
|
||
((PBINDING_CONTEXT)hObject)->ulFunctionalZeroBits = ~((PBINDING_CONTEXT)hObject)->Functional.ulAddress;
|
||
Status = UpdateFunctionalAddress(((PBINDING_CONTEXT)hObject)->pAdapterContext);
|
||
break;
|
||
|
||
case DLC_INFO_CLASS_SET_MULTICAST:
|
||
memcpy(&((PBINDING_CONTEXT)hObject)->usBroadcastAddress,
|
||
pSetInfo->auchBuffer,
|
||
6
|
||
);
|
||
Status = UpdateFunctionalAddress(((PBINDING_CONTEXT)hObject)->pAdapterContext);
|
||
break;
|
||
|
||
default:
|
||
return DLC_STATUS_INVALID_COMMAND;
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
|
||
DLC_STATUS
|
||
UpdateFunctionalAddress(
|
||
IN PADAPTER_CONTEXT pAdapterContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Procedure first makes inclusive or between the functionl address of
|
||
this process context and the functional address defined
|
||
for all bindings and then saves the new functional address to NDIS.
|
||
The NT mutex makes this operation atomic.
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - LLC context of the current adapter
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR aMulticastList[LLC_MAX_MULTICAST_ADDRESS * 6];
|
||
TR_BROADCAST_ADDRESS NewFunctional;
|
||
UINT MulticastListSize;
|
||
ULONG CurrentMulticast;
|
||
PBINDING_CONTEXT pBinding;
|
||
UINT i;
|
||
NDIS_STATUS Status;
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
NewFunctional.ulAddress = 0;
|
||
|
||
//
|
||
// We cannot be setting several functional addresses simultanously!
|
||
//
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
KeWaitForSingleObject(&NdisAccessMutex, UserRequest, KernelMode, FALSE, NULL);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
//
|
||
// The access to global data structures must be procted by
|
||
// the spin lock.
|
||
//
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
||
|
||
for (pBinding = pAdapterContext->pBindings; pBinding; pBinding = pBinding->pNext) {
|
||
NewFunctional.ulAddress |= pBinding->Functional.ulAddress;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
||
|
||
if ((pAdapterContext->NdisMedium == NdisMedium802_3)
|
||
|| (pAdapterContext->NdisMedium == NdisMediumFddi)) {
|
||
|
||
//
|
||
// Each bit in the functional address is translated
|
||
// to a ethernet multicast address.
|
||
// The bit order within byte has already been swapped.
|
||
//
|
||
|
||
CurrentMulticast = 1;
|
||
MulticastListSize = 0;
|
||
for (i = 0; i < 31; i++) {
|
||
if (CurrentMulticast & NewFunctional.ulAddress) {
|
||
aMulticastList[MulticastListSize] = 0x03;
|
||
aMulticastList[MulticastListSize + 1] = 0;
|
||
LlcMemCpy(&aMulticastList[MulticastListSize + 2],
|
||
&CurrentMulticast,
|
||
sizeof(CurrentMulticast)
|
||
);
|
||
MulticastListSize += 6;
|
||
}
|
||
CurrentMulticast <<= 1;
|
||
}
|
||
|
||
//
|
||
// Add the group addresses of all bindings behind
|
||
// the functional addresses in the table.
|
||
//
|
||
|
||
for (pBinding = pAdapterContext->pBindings; pBinding; pBinding = pBinding->pNext) {
|
||
|
||
//
|
||
// We may drop some group addresses, but I don't expect that
|
||
// it will ever happen (i don't know anybody using tr
|
||
// group address, the possibility to have all functional
|
||
// address bits in use and more than one group address in system
|
||
// is almost impossible)
|
||
//
|
||
|
||
if (pBinding->ulBroadcastAddress != 0
|
||
&& MulticastListSize < LLC_MAX_MULTICAST_ADDRESS * 6) {
|
||
|
||
//
|
||
// Set the default bits in the group address,
|
||
// but use ethernet bit order.
|
||
//
|
||
|
||
LlcMemCpy(&aMulticastList[MulticastListSize],
|
||
&pBinding->usBroadcastAddress,
|
||
6
|
||
);
|
||
MulticastListSize += 6;
|
||
}
|
||
}
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
Status = SetNdisParameter(pAdapterContext,
|
||
(pAdapterContext->NdisMedium == NdisMediumFddi)
|
||
? OID_FDDI_LONG_MULTICAST_LIST
|
||
: OID_802_3_MULTICAST_LIST,
|
||
aMulticastList,
|
||
MulticastListSize
|
||
);
|
||
} else {
|
||
|
||
//
|
||
// The functional address bit (bit 0) must be always reset!
|
||
//
|
||
|
||
NewFunctional.auchAddress[0] &= ~0x80;
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
Status = SetNdisParameter(pAdapterContext,
|
||
OID_802_5_CURRENT_FUNCTIONAL,
|
||
&NewFunctional,
|
||
sizeof(NewFunctional)
|
||
);
|
||
}
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
KeReleaseMutex(&NdisAccessMutex, FALSE);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
return DLC_STATUS_INVALID_FUNCTIONAL_ADDRESS;
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
DLC_STATUS
|
||
UpdateGroupAddress(
|
||
IN PADAPTER_CONTEXT pAdapterContext,
|
||
IN PBINDING_CONTEXT pBindingContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Procedure updates token-ring' group address.
|
||
It is converted automatically multicast address
|
||
on the ethernet.
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - describes adapter to update group addresses for
|
||
pBindingContext - describes binding context
|
||
|
||
Return Value:
|
||
|
||
DLC_STATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NDIS_STATUS Status;
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
if ((pAdapterContext->NdisMedium == NdisMedium802_3)
|
||
|| (pAdapterContext->NdisMedium == NdisMediumFddi)) {
|
||
|
||
PUCHAR pMulticastAddress = (PUCHAR)&pBindingContext->usBroadcastAddress;
|
||
|
||
pMulticastAddress[0] = 0x03;
|
||
pMulticastAddress[1] = 0;
|
||
pMulticastAddress[2] |= 1;
|
||
|
||
//
|
||
// Because functional and group addresses are mapped into
|
||
// the multicast addresses, the updated global multicast list
|
||
// must inlcude both address types of all bindings,
|
||
//
|
||
|
||
Status = UpdateFunctionalAddress(pAdapterContext);
|
||
return Status;
|
||
} else {
|
||
|
||
PUCHAR pGroupAddress = (PUCHAR)&pBindingContext->usBroadcastAddress;
|
||
|
||
pGroupAddress[0] = 0xC0;
|
||
pGroupAddress[1] = 0;
|
||
|
||
//
|
||
// The group/functional address bit must be always set!
|
||
//
|
||
|
||
pGroupAddress[2] |= 0x80;
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
Status = SetNdisParameter(pAdapterContext,
|
||
OID_802_5_CURRENT_GROUP,
|
||
&pGroupAddress[2],
|
||
4
|
||
);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
//
|
||
// The error status code is wrong, but IBM has defined no
|
||
// error code for this case.
|
||
//
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
return DLC_STATUS_INVALID_FUNCTIONAL_ADDRESS;
|
||
} else {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
}
|