mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
678 lines
21 KiB
678 lines
21 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|