windows-nt/Source/XPSP1/NT/net/dlc/driver/llclink.c
2020-09-26 16:20:57 +08:00

1092 lines
30 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Copyright (c) 1991 Nokia Data Systems Ab
Module Name:
llclink.c
Abstract:
The module implements the open, connect and close primitives
for a link station object. The link stations have also been
initialized within this module.
Contents:
LlcOpenLinkStation
LlcConnectStation
InitiateAsyncLinkCommand
LlcDisconnectStation
LlcFlowControl
LinkFlowControl
SearchLinkAddress
SetLinkParameters
CheckLinkParameters
CopyLinkParameters
CopyNonZeroBytes
RunInterlockedStateMachineCommand
Author:
Antti Saarenheimo (o-anttis) 28-MAY-1991
Revision History:
--*/
#include <llc.h>
DLC_STATUS
LlcOpenLinkStation(
IN PLLC_SAP pSap,
IN UCHAR DestinationSap,
IN PUCHAR pDestinationAddress OPTIONAL,
IN PUCHAR pReceivedLanHeader OPTIONAL,
IN PVOID hClientStation,
OUT PVOID* phLlcHandle
)
/*++
Routine Description:
creates a DATA_LINK structure and fills it in. Called either as a result
of receiving a SABME, or via DLC.OPEN.STATION
This operation is the same as ACTIVATE_LS primitive in IBM TR Arch. ref.
Arguments:
pSap - pointer to SAP
DestinationSap - remote SAP number
pDestinationAddress - remote node address. If this function is being called
as a result of receiving a SABME for a new link then
this parameter is NULL
pReceivedLanHeader - LAN header as received off the wire, containing source
and destination adapter addresses, optional source
routing and source and destination SAPs
hClientStation - handle (address) of LLC client's link station object
phLlcHandle - pointer to returned handle (address) to LLC DATA_LINK
object
Return Value:
DLC_STATUS
Success - STATUS_SUCCESS
link station has been opened successfully
Failure - DLC_STATUS_INVALID_SAP_VALUE
the link station already exists or the SAP is really invalid.
DLC_NO_MEMORY
there was no free preallocated link station
--*/
{
PDATA_LINK pLink;
PDATA_LINK* ppLink;
PADAPTER_CONTEXT pAdapterContext = pSap->Gen.pAdapterContext;
DLC_STATUS LlcStatus = STATUS_SUCCESS;
UINT AddressTranslation;
//
// We need a temporary buffer to build lan header for link,
// because user may use different ndis medium from network.
//
UCHAR auchTempBuffer[32];
ASSUME_IRQL(DISPATCH_LEVEL);
LlcZeroMem(auchTempBuffer, sizeof(auchTempBuffer));
if (pSap->Gen.ObjectType != LLC_SAP_OBJECT) {
return DLC_STATUS_INVALID_SAP_VALUE;
}
ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
pLink = (PDATA_LINK)ALLOCATE_PACKET_LLC_LNK(pAdapterContext->hLinkPool);
if (pLink == NULL) {
LlcStatus = DLC_STATUS_NO_MEMORY;
goto ErrorExit;
}
//
// This reference keeps the object alive, until it is dereferenced
// in the delete.
//
ReferenceObject(pLink);
//
// LLC driver have two different address formats:
//
// 1. External format of the binding (ethernet or token-ring,
// DLC driver uses always token-ring format, the ethernet
// support is compiled in conditionally.
//
// 2. Internal send format (always the actual lan type,
// ethernet, dix or tokenring). The user provides link
// address in its own mode and we must build the actual
// lan link header from it.
//
if (pDestinationAddress != NULL) {
//
// link created by DLC.CONNECT.STATION
//
AddressTranslation = pSap->Gen.pLlcBinding->AddressTranslation;
LlcBuildAddress(pSap->Gen.pLlcBinding->NdisMedium,
pDestinationAddress,
NULL,
auchTempBuffer
);
} else {
//
// link created by incoming SABME
//
pLink->Flags |= DLC_ACTIVE_REMOTE_CONNECT_REQUEST;
AddressTranslation = pAdapterContext->AddressTranslationMode;
LlcBuildAddressFromLanHeader(pAdapterContext->NdisMedium,
pReceivedLanHeader,
auchTempBuffer
);
}
//
// We want to use always DIX lan headers in the token-ring case
//
if (AddressTranslation == LLC_SEND_802_5_TO_802_3) {
AddressTranslation = LLC_SEND_802_5_TO_DIX;
} else if (AddressTranslation == LLC_SEND_802_3_TO_802_3) {
AddressTranslation = LLC_SEND_802_3_TO_DIX;
}
//
// Now we can build the actual network header for the sending
// (this same routine build lan header also for all
// other packet types)
//
pLink->cbLanHeaderLength = CopyLanHeader(AddressTranslation,
auchTempBuffer,
pAdapterContext->NodeAddress,
pLink->auchLanHeader,
pAdapterContext->ConfigInfo.SwapAddressBits
);
//
// We always build a DIX header but it is only used when the Ethernet type
// is actually DIX
//
if (pAdapterContext->NdisMedium == NdisMedium802_3
&& pSap->Gen.pLlcBinding->EthernetType != LLC_ETHERNET_TYPE_DIX) {
pLink->cbLanHeaderLength = 14;
}
//
// Save the client handle, but reset and initailize everything else.
// The link must be ready for any kind extrnal inputs when
// we will connenct it to the hash table of the link stations.
// (actually that's not true now, because we init the link to
// LINK_CLOSED state, but we may change the state machine.
// It would be a different thing with a 802.2 state machine)
//
pLink->Gen.ObjectType = LLC_LINK_OBJECT;
//
// RLF 07/22/92. The link state should be DISCONNECTED so that we can
// accept incoming SABMEs for this SAP/link station. This is also
// according to IBM LAN Tech. Ref. p. 2-33. It is safe to set the
// DISCONNECTED state now because we have the send and object database
// spin locks, so we can't get interrupted by NDIS driver
//
//
// RLF 08/13/92. Ho Hum. This still isn't correct - we must put the link
// into different states depending on how its being opened - DISCONNECTED
// if the upper layers are creating the link, or LINK_CLOSED if we're
// creating the link as a result of receiving a SABME. Use pReceivedLanHeader
// as a flag: DLC calls this routine with this parameter set to NULL
//
////pLink->State = LINK_CLOSED;
//pLink->State = DISCONNECTED;
pLink->State = pReceivedLanHeader ? LINK_CLOSED : DISCONNECTED;
//
// RLF 10/01/92. We need some way of knowing that the link station was
// created by receiving a SABME. We need this to decide what to do with
// the source routing info in a subsequent DLC.CONNECT.STATION command.
// This field used to be Reserved
//
pLink->RemoteOpen = hClientStation == NULL;
//
// RLF 05/09/94
//
// We set the framing type to unspecified. This field is only used if the
// adapter was opened in AUTO mode. It will be set to 802.3 or DIX by the
// SABME received processing (new link created by remote station) or when
// the first UA is received in response to the 2 SABMEs we send out (802.3
// and DIX)
//
pLink->FramingType = (ULONG)LLC_SEND_UNSPECIFIED;
pLink->Gen.hClientHandle = hClientStation;
pLink->Gen.pAdapterContext = pAdapterContext;
pLink->pSap = pSap;
pLink->Gen.pLlcBinding = pSap->Gen.pLlcBinding;
//
// Save the node addresses used in link station
//
pDestinationAddress = pLink->auchLanHeader;
if (pAdapterContext->NdisMedium == NdisMedium802_5) {
pDestinationAddress += 2;
} else if (pAdapterContext->NdisMedium == NdisMediumFddi) {
++pDestinationAddress;
}
memcpy(pLink->LinkAddr.Node.auchAddress, pDestinationAddress, 6);
//
// RLF 03/24/93
//
// if we're talking Ethernet or DIX, we need to report the bit-flipped
// address at the DLC interface
//
SwapMemCpy((BOOLEAN)((AddressTranslation == LLC_SEND_802_3_TO_DIX)
|| (pAdapterContext->NdisMedium == NdisMediumFddi)),
pLink->DlcStatus.auchRemoteNode,
pDestinationAddress,
6
);
//
// Four different local saps: my code would need a cleanup
// (four bytes doesn't use very much memory on the other hand)
//
pLink->LinkAddr.Address.DestSap = pLink->DlcStatus.uchRemoteSap = pLink->Dsap = DestinationSap;
pLink->LinkAddr.Address.SrcSap = pLink->DlcStatus.uchLocalSap = pLink->Ssap = (UCHAR)pSap->SourceSap;
pLink->DlcStatus.hLlcLinkStation = (PVOID)pLink;
pLink->SendQueue.pObject = pLink;
InitializeListHead(&pLink->SendQueue.ListHead);
InitializeListHead(&pLink->SentQueue);
pLink->Flags |= DLC_SEND_DISABLED;
//
// The next procedure returns the pointer of the slot for the
// new link station pointer. The address may be in the
// hash table or it may be the address of pRigth or pLeft
// field within another link station structure.
//
ppLink = SearchLinkAddress(pAdapterContext, pLink->LinkAddr);
//
// this link station must not yet be in the table
// of active link stations. If its slot is
// empty, then save the new link station to the
// list of the active link stations.
//
if (*ppLink != NULL) {
LlcStatus = DLC_STATUS_INVALID_SAP_VALUE;
DEALLOCATE_PACKET_LLC_LNK(pAdapterContext->hLinkPool, pLink);
} else {
pLink->Gen.pNext = (PLLC_OBJECT)pSap->pActiveLinks;
pSap->pActiveLinks = pLink;
//
// Set the default link parameters,
// Note: This creates the timer ticks. They must
// be deleted with the terminate timer function,
// when the link station is closed.
//
LlcStatus = SetLinkParameters(pLink, (PUCHAR)&pSap->DefaultParameters);
if (LlcStatus != STATUS_SUCCESS) {
//
// We may have been started T1 and T2 timers.
//
TerminateTimer(pAdapterContext, &pLink->T1);
TerminateTimer(pAdapterContext, &pLink->T2);
DEALLOCATE_PACKET_LLC_LNK(pAdapterContext->hLinkPool, pLink);
} else {
//
// N2 is never initilaized by IBM state machine, when
// the link is created by a remote connect request.
// The link can be killed by this combination of state
// transmitions:
// (LINK_OPENED),
// (RNR-r => REMOTE_BUSY),
// (RR-c => CHECKPOINTING)
// (T1 timeout => DISCONNECTED) !!!!!
//
// This will fix the bug in IBM state machine:
//
pLink->P_Ct = pLink->N2;
*ppLink = *phLlcHandle = (PVOID)pLink;
pAdapterContext->ObjectCount++;
}
}
ErrorExit:
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
return LlcStatus;
}
VOID
LlcBindLinkStation(
IN PDATA_LINK pStation,
IN PVOID hClientHandle
)
{
pStation->Gen.hClientHandle = hClientHandle;
}
VOID
LlcConnectStation(
IN PDATA_LINK pStation,
IN PLLC_PACKET pPacket,
IN PVOID pSourceRouting OPTIONAL,
IN PUSHORT pusMaxInformationField
)
/*++
Routine Description:
The upper level protocol may call this primitive to initiate
the connection negotiation with a remote link station,
to accept the connection request or to reconnect a link station
that have been disconnected for some reason with a new source
routing information.
The command is completed asynchronously and the status
is returned as an event.
The primitive is the same as SET_ABME primitive in "IBM TR Architecture
reference".
The function implements also CONNECT_REQUEST and CONNECT_RESPONSE
primitives of IEEE 802.2.
Arguments:
pStation - address of link station
pPacket - command completion packet
pSourceRouting - optional source routing information. This must
be NULL if the source routing information is not
used
pusMaxInformationField - the maximum data size possible to use with this
connection. The source routing bridges may
decrease the maximum information field size.
Otherwise the maximum length is used
Return Value:
None.
--*/
{
NDIS_MEDIUM NdisMedium = pStation->Gen.pAdapterContext->NdisMedium;
if (pSourceRouting) {
//
// We first read the destination address from the
// lan header and then extend the source routing
// field in the LAN header of link.
//
if (NdisMedium == NdisMedium802_5) {
//
// RLF 10/01/92. If RemoteOpen is TRUE then the link was opened
// due to receiving a SABME and we ignore the source routing info
// (we already got it from the SABME packet)
//
if (!pStation->RemoteOpen) {
pStation->cbLanHeaderLength = (UCHAR)LlcBuildAddress(
NdisMedium,
&pStation->auchLanHeader[2],
pSourceRouting,
pStation->auchLanHeader
);
}
} else {
pSourceRouting = NULL;
}
}
*pusMaxInformationField = LlcGetMaxInfoField(NdisMedium,
pStation->Gen.pLlcBinding,
pStation->auchLanHeader
);
pStation->MaxIField = *pusMaxInformationField;
pStation->Flags &= ~DLC_ACTIVE_REMOTE_CONNECT_REQUEST;
//
// Activate the link station at first, the remotely connected
// link station is already active and in that case the state
// machine return logical error from ACTIVATE_LS input.
//
RunInterlockedStateMachineCommand(pStation, ACTIVATE_LS);
InitiateAsyncLinkCommand(pStation, pPacket, SET_ABME, LLC_CONNECT_COMPLETION);
}
VOID
InitiateAsyncLinkCommand(
IN PDATA_LINK pLink,
IN PLLC_PACKET pPacket,
IN UINT StateMachineCommand,
IN UINT CompletionCode
)
/*++
Routine Description:
Initiates or removes an LLC link. We have a link station in the DISCONNECTED
state. We are either sending a SABME or DISC
Arguments:
pLink - pointer to LLC link station structure ('object')
pPacket - pointer to packet to use for transmission
StateMachineCommand - command given to the state machine
CompletionCode - completion command type returned asynchronously
Return Value:
None.
--*/
{
PADAPTER_CONTEXT pAdapterContext = pLink->Gen.pAdapterContext;
UINT Status;
//
// link will return an error status if it is already connected.
//
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
AllocateCompletionPacket(pLink, CompletionCode, pPacket);
//
// After RunStateMachineCommand
// the link may be deleted in any time by an NDIS command completion
// indication (send or receive) => we must not use link after this
//
Status = RunStateMachineCommand(pLink, StateMachineCommand);
//
// IBM state machine does not stop the send process => we
// must do it here we will get a system bug check.
//
if (StateMachineCommand == SET_ADM) {
DisableSendProcess(pLink);
}
//
// disconnect or connect commands may fail, because there are
// not enough memory to allocate packets for them.
// In that case we must complete the command here with an error code.
//
if (Status != STATUS_SUCCESS) {
QueueCommandCompletion((PLLC_OBJECT)pLink, CompletionCode, Status);
}
BackgroundProcessAndUnlock(pAdapterContext);
}
VOID
LlcDisconnectStation(
IN PDATA_LINK pLink,
IN PLLC_PACKET pPacket
)
/*++
Routine Description:
The primtive initiates the disconnection handshaking. The upper
protocol must wait LLC_EVENT_DISCONNECTED event before it can close
the link station. The link station must either be closed or
reconnected after a disconnection event. The DLC driver
disconnects the link only when it is closed.
This operation is the same as SET_ADM primitive in IBM TR Arch. ref.
Arguments:
hStation - link station handle.
hRequestHandle - opaque handle returned when the command completes
Return Value:
None
Complete always asynchronously by calling the
command completion routine.
--*/
{
//
// We don't want send yet another DM, if the link station has
// already disconnected. We don't modify the state machine,
// because the state machine should be as orginal as possible.
//
if (pLink->State == DISCONNECTED) {
pPacket->Data.Completion.CompletedCommand = LLC_DISCONNECT_COMPLETION;
pPacket->Data.Completion.Status = STATUS_SUCCESS;
pLink->Gen.pLlcBinding->pfCommandComplete(
pLink->Gen.pLlcBinding->hClientContext,
pLink->Gen.hClientHandle,
pPacket
);
} else {
InitiateAsyncLinkCommand(
pLink,
pPacket,
SET_ADM,
LLC_DISCONNECT_COMPLETION
);
}
}
DLC_STATUS
LlcFlowControl(
IN PLLC_OBJECT pStation,
IN UCHAR FlowControlState
)
/*++
Routine Description:
The primitive sets or resets the local busy state of a single
link station or all link stations of a sap.
The routine also maintains the local busy user
and local busy buffer states, that are returned in link station
status query, because the IBM state machine support only one buffer
busy state.
Arguments:
pStation - link station handle.
FlowControlState - new flow control command bits set for the link station.
The parameter is a bit field:
0 => Sets LOCAL_BUSY_USER state
0x80 => resets LOCAL_BUSY_USER state
0x40 => resets LOCAL_BUSY_BUFFER state
0xC0 => resets both local busy states
Return Value:
STATUS_SUCCESS
--*/
{
PDATA_LINK pLink;
UINT Status = STATUS_SUCCESS;
PADAPTER_CONTEXT pAdapterContext = pStation->Gen.pAdapterContext;
ASSUME_IRQL(DISPATCH_LEVEL);
//
// We must prevent any LLC object to be deleted, while we
// are updating the flow control states
//
ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
if (pStation->Gen.ObjectType != LLC_LINK_OBJECT) {
if (pStation->Gen.ObjectType == LLC_SAP_OBJECT) {
for (pLink = pStation->Sap.pActiveLinks;
pLink != NULL;
pLink = (PDATA_LINK)pLink->Gen.pNext) {
Status |= LinkFlowControl(pLink, FlowControlState);
}
} else {
Status = DLC_STATUS_INVALID_STATION_ID;
}
} else {
Status = LinkFlowControl((PDATA_LINK)pStation, FlowControlState);
}
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
BackgroundProcess(pAdapterContext);
return Status;
}
DLC_STATUS
LinkFlowControl(
IN PDATA_LINK pLink,
IN UCHAR FlowControlState
)
/*++
Routine Description:
The primitive sets or resets the local busy state for a
single link. The routine also maintains the local busy user
and local busy buffer states.
This level do not care about the interlocking.
It is done on the upper level.
Arguments:
hStation - link station handle.
FlowControlState - new flow control command bits set for the link station.
Return Value:
STATUS_SUCCESS
--*/
{
if ((FlowControlState & 0x80) == 0) {
//
// Bit5 is used as an undocumented flag, that sets
// the link local busy buffer state. We need this
// in the DOS DLC emulation.
//
ACQUIRE_SPIN_LOCK(&pLink->Gen.pAdapterContext->SendSpinLock);
if (FlowControlState == LLC_SET_LOCAL_BUSY_BUFFER) {
pLink->Flags |= DLC_LOCAL_BUSY_BUFFER;
} else {
pLink->Flags |= DLC_LOCAL_BUSY_USER;
}
RELEASE_SPIN_LOCK(&pLink->Gen.pAdapterContext->SendSpinLock);
return RunInterlockedStateMachineCommand(pLink, ENTER_LCL_Busy);
} else {
//
// Optimize the buffer enabling, because RECEICE for a
// SAP station should disable any non user busy states of
// all link stations defined for sap (may take a long
// time if a sap has very may links)
//
if (FlowControlState == LLC_RESET_LOCAL_BUSY_BUFFER) {
FlowControlState = DLC_LOCAL_BUSY_BUFFER;
} else {
FlowControlState = DLC_LOCAL_BUSY_USER;
}
if (pLink->Flags & FlowControlState) {
ACQUIRE_SPIN_LOCK(&pLink->Gen.pAdapterContext->SendSpinLock);
pLink->Flags &= ~FlowControlState;
RELEASE_SPIN_LOCK(&pLink->Gen.pAdapterContext->SendSpinLock);
if ((pLink->Flags & (DLC_LOCAL_BUSY_USER | DLC_LOCAL_BUSY_BUFFER)) == 0) {
return RunInterlockedStateMachineCommand(pLink, EXIT_LCL_Busy);
}
} else {
return DLC_STATUS_LINK_PROTOCOL_ERROR;
}
}
return STATUS_SUCCESS;
}
#if LLC_DBG >= 2
PDATA_LINK
SearchLink(
IN PADAPTER_CONTEXT pAdapterContext,
IN LAN802_ADDRESS LanAddr
)
/*++
Routine Description:
The routine searches a link from the hash table.
All links in the same hash node has been saved to a simple
link list.
Note: the full link address is actually 61 bits long =
7 (SSAP) + 7 (DSAP) + 47 (any non-broadcast source address).
We save the address information into two ULONGs, that are used
in the actual search. The hash key will be calculated by xoring
all 8 bytes in the address.
Arguments:
pAdapterContext - MAC adapter context of data link driver
LanAddr - the complete 64 bit address of link (48 bit source addr + saps)
Return Value:
PDATA_LINK - pointer to LLC link object or NULL if not found
--*/
{
USHORT usHash;
PDATA_LINK pLink;
// this is a very simple hash algorithm, but result is modified
// by all bits => it should be good enough for us.
usHash =
LanAddr.aus.Raw[0] ^ LanAddr.aus.Raw[1] ^
LanAddr.aus.Raw[2] ^ LanAddr.aus.Raw[3];
pLink =
pAdapterContext->aLinkHash[
((((PUCHAR)&usHash)[0] ^ ((PUCHAR)&usHash)[1]) % LINK_HASH_SIZE)];
//
// Search the first matching link in the link list.
//
while (pLink != NULL &&
(pLink->LinkAddr.ul.Low != LanAddr.ul.Low ||
pLink->LinkAddr.ul.High != LanAddr.ul.High))
{
pLink = pLink->pNextNode;
}
return pLink;
}
#endif
PDATA_LINK*
SearchLinkAddress(
IN PADAPTER_CONTEXT pAdapterContext,
IN LAN802_ADDRESS LanAddr
)
/*++
Routine Description:
The routine searches the address of a link pointer in the hash table.
All links in the same hash node has been saved to a simple
link list.
Note: the full link address is actually 61 bits long =
7 (SSAP) + 7 (DSAP) + 47 (any non-broadcast source address).
We save the address information into two ULONGs, that are used
in the actual search. The hash key will be calculated by xoring
all 8 bytes in the address.
Arguments:
pAdapterContext - MAC adapter context of data link driver
LanAddr - the complete 64 bits address of link (48 bit source addr + saps)
Return Value:
PDATA_LINK - pointer to LLC link object or NULL if not found
--*/
{
USHORT usHash;
PDATA_LINK *ppLink;
//
// this is a very simple hash algorithm, but result is modified
// by all bits => it should be quite good enough
//
usHash = LanAddr.aus.Raw[0]
^ LanAddr.aus.Raw[1]
^ LanAddr.aus.Raw[2]
^ LanAddr.aus.Raw[3];
ppLink = &pAdapterContext->aLinkHash[((((PUCHAR)&usHash)[0]
^ ((PUCHAR)&usHash)[1])
% LINK_HASH_SIZE)];
//
// BUG-BUG-BUG Check, that the C- compliler produces optimal
// dword compare for this.
//
while (*ppLink != NULL
&& ((*ppLink)->LinkAddr.ul.Low != LanAddr.ul.Low
|| (*ppLink)->LinkAddr.ul.High != LanAddr.ul.High)) {
ppLink = &(*ppLink)->pNextNode;
}
return ppLink;
}
DLC_STATUS
SetLinkParameters(
IN OUT PDATA_LINK pLink,
IN PUCHAR pNewParameters
)
/*++
Routine Description:
Updates new parameters for a link station and reinitializes the
timers and window counters.
Arguments:
pLink - LLC link station object
pNewParameters - new parameters set to a link station
Return Value:
None.
--*/
{
DLC_STATUS LlcStatus;
USHORT MaxInfoField;
CopyLinkParameters((PUCHAR)&pLink->TimerT1,
pNewParameters,
(PUCHAR)&pLink->pSap->DefaultParameters
);
//
// The application cannot set bigger information field than
// supported by adapter and source routing bridges.
//
MaxInfoField = LlcGetMaxInfoField(pLink->Gen.pAdapterContext->NdisMedium,
pLink->Gen.pLlcBinding,
pLink->auchLanHeader
);
if (pLink->MaxIField > MaxInfoField) {
pLink->MaxIField = MaxInfoField;
}
//
// The initial transmit and receive window size (Ww) has
// a fixed initial value, because it is dynamic, but we must
// set it always smaller than maxout.
// The maxin value is fixed. The dynamic management of N3
// is not really worth of the effort. By default, when it is
// set to maximum 127, the sender searches the optimal window
// size using the pool-bit.
//
pLink->N3 = pLink->RW;
pLink->Ww = 16; // 8 * 2;
pLink->MaxOut *= 2;
pLink->TW = pLink->MaxOut;
if (pLink->TW < pLink->Ww) {
pLink->Ww = pLink->TW;
}
LlcStatus = InitializeLinkTimers(pLink);
return LlcStatus;
}
DLC_STATUS
CheckLinkParameters(
PDLC_LINK_PARAMETERS pParms
)
/*++
Routine Description:
Procedure checks the new parameters to be set for a link and returns
error status if any of them is invalid.
Arguments:
pLink - LLC link station object
pNewParameters - new parameters set to a link station
Return Value:
None
--*/
{
//
// These maximum values have been defined in IBM LAN Tech-Ref
//
if (pParms->TimerT1 > 10
|| pParms->TimerT2 > 10
|| pParms->TimerTi > 10
|| pParms->MaxOut > 127
|| pParms->MaxIn > 127
|| pParms->TokenRingAccessPriority > 3) {
return DLC_STATUS_PARMETERS_EXCEEDED_MAX;
} else {
return STATUS_SUCCESS;
}
}
//
// Copies all non-null new link parameters, the default values are
// used when the new values are nul. Used by SetLinkParameters and
// and SetInfo call of sap station.
//
VOID
CopyLinkParameters(
OUT PUCHAR pOldParameters,
IN PUCHAR pNewParameters,
IN PUCHAR pDefaultParameters
)
{
//
// We must use the default value, if somebody has set nul.
// All parameters are UCHARs => we can do the check for a byte stream
//
CopyNonZeroBytes(pOldParameters,
pNewParameters,
pDefaultParameters,
sizeof(DLC_LINK_PARAMETERS) - sizeof(USHORT)
);
//
// The information field is the only non-UCHAR value among the
// link station parameters.
//
if (((PDLC_LINK_PARAMETERS)pNewParameters)->MaxInformationField != 0) {
((PDLC_LINK_PARAMETERS)pOldParameters)->MaxInformationField =
((PDLC_LINK_PARAMETERS)pNewParameters)->MaxInformationField;
} else if (((PDLC_LINK_PARAMETERS)pOldParameters)->MaxInformationField == 0) {
((PDLC_LINK_PARAMETERS)pOldParameters)->MaxInformationField =
((PDLC_LINK_PARAMETERS)pDefaultParameters)->MaxInformationField;
}
}
VOID
CopyNonZeroBytes(
OUT PUCHAR pOldParameters,
IN PUCHAR pNewParameters,
IN PUCHAR pDefaultParameters,
IN UINT Length
)
/*++
Routine Description:
Copies and filters DLC parameter values. If the value is 0, the corresponding
default is used, else the supplied value
Arguments:
pOldParameters - pointer to set of UCHAR values
pNewParameters - pointer to array of output values
pDefaultParameters - pointer to corresponding default values
Length - size of values in bytes (UCHARs)
Return Value:
None.
--*/
{
UINT i;
for (i = 0; i < Length; i++) {
if (pNewParameters[i] != 0) {
pOldParameters[i] = pNewParameters[i];
} else if (pOldParameters[i] == 0) {
pOldParameters[i] = pDefaultParameters[i];
}
}
}
UINT
RunInterlockedStateMachineCommand(
IN PDATA_LINK pStation,
IN USHORT Command
)
/*++
Routine Description:
Runs the state machine for a link, within the adapter's SendSpinLock (&
therefore at DPC)
Arguments:
pStation - pointer to DATA_LINK structure describing this link station
Command - state machine command to be run
Return Value:
UINT
Status from RunStateMachineCommand
--*/
{
UINT Status;
ACQUIRE_SPIN_LOCK(&pStation->Gen.pAdapterContext->SendSpinLock);
Status = RunStateMachineCommand(pStation, Command);
RELEASE_SPIN_LOCK(&pStation->Gen.pAdapterContext->SendSpinLock);
return Status;
}