1007 lines
26 KiB
C
1007 lines
26 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
Copyright (c) 1991 Nokia Data Systems Ab
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
llcobj.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
The module implements the open and close primitives
|
|||
|
for all data link driver objects.
|
|||
|
|
|||
|
Contents:
|
|||
|
LlcOpenStation
|
|||
|
LlcCloseStation
|
|||
|
CompleteClose
|
|||
|
CancelTransmitCommands
|
|||
|
CancelTransmitsInQueue
|
|||
|
LlcSetDirectOpenOptions
|
|||
|
CompleteObjectDelete
|
|||
|
CompletePendingLlcCommand
|
|||
|
LlcDereferenceObject
|
|||
|
LlcReferenceObject
|
|||
|
LlcGetReceivedLanHeaderLength
|
|||
|
LlcGetEthernetType
|
|||
|
LlcGetCommittedSpace
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Antti Saarenheimo (o-anttis) 29-MAY-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#if DBG
|
|||
|
#ifndef i386
|
|||
|
#define LLC_PRIVATE_PROTOTYPES
|
|||
|
#endif
|
|||
|
#include "dlc.h" // need DLC_FILE_CONTEXT for memory charged to file handle
|
|||
|
#endif
|
|||
|
|
|||
|
#include <llc.h>
|
|||
|
|
|||
|
static USHORT ObjectSizes[] = {
|
|||
|
sizeof(LLC_STATION_OBJECT), // direct station
|
|||
|
sizeof(LLC_SAP ), // SAP station
|
|||
|
sizeof(LLC_STATION_OBJECT), // group SAP
|
|||
|
(USHORT)(-1), // link station
|
|||
|
sizeof(LLC_STATION_OBJECT) // DIX station
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
DLC_STATUS
|
|||
|
LlcOpenStation(
|
|||
|
IN PBINDING_CONTEXT pBindingContext,
|
|||
|
IN PVOID hClientHandle,
|
|||
|
IN USHORT ObjectAddress,
|
|||
|
IN UCHAR ObjectType,
|
|||
|
IN USHORT OpenOptions,
|
|||
|
OUT PVOID* phStation
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The primitive opens a LLC SAP exclusively for the upper protocol
|
|||
|
driver. The upper protocol must provide the storage for the
|
|||
|
SAP object. The correct size of the object has been defined in the
|
|||
|
characteristics table of the LLC driver.
|
|||
|
|
|||
|
The first call to a new adapter initializes also the NDIS interface
|
|||
|
and allocates internal data structures for the new adapter.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pBindingContext - binding context of the llc client
|
|||
|
hClientHandle - The client protocol gets this handle in all indications
|
|||
|
of the SAP
|
|||
|
ObjectAddress - LLC SAP number or dix
|
|||
|
ObjectType - type of the created object
|
|||
|
OpenOptions - various open options set for the new object
|
|||
|
phStation - returned opaque handle
|
|||
|
|
|||
|
Special: Must be called IRQL < DPC (at least when direct station opened)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DLC_STATUS
|
|||
|
Success - STATUS_SUCCESS
|
|||
|
Failure - DLC_STATUS_NO_MEMORY
|
|||
|
DLC_STATUS_INVALID_SAP_VALUE
|
|||
|
DLC_STATUS_INVALID_OPTION
|
|||
|
DLC_STATUS_INVALID_STATION_ID
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER_CONTEXT pAdapterContext;
|
|||
|
PLLC_OBJECT pStation;
|
|||
|
DLC_STATUS LlcStatus = STATUS_SUCCESS;
|
|||
|
PVOID* ppListBase;
|
|||
|
ULONG PacketFilter;
|
|||
|
|
|||
|
#if DBG
|
|||
|
PDLC_FILE_CONTEXT pFileContext = (PDLC_FILE_CONTEXT)(pBindingContext->hClientContext);
|
|||
|
#endif
|
|||
|
|
|||
|
pAdapterContext = pBindingContext->pAdapterContext;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate and initialize the SAP, but do not yet connect
|
|||
|
// it to the adapter
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(ObjectSizes[ObjectType] != (USHORT)(-1));
|
|||
|
|
|||
|
pStation = (PLLC_OBJECT)ALLOCATE_ZEROMEMORY_FILE(ObjectSizes[ObjectType]);
|
|||
|
|
|||
|
if (pStation == NULL) {
|
|||
|
return DLC_STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
if (ObjectType == LLC_SAP_OBJECT && (ObjectAddress & 1)) {
|
|||
|
ObjectType = LLC_GROUP_SAP_OBJECT;
|
|||
|
ASSERT(phStation);
|
|||
|
}
|
|||
|
|
|||
|
pStation->Gen.hClientHandle = hClientHandle;
|
|||
|
pStation->Gen.pLlcBinding = pBindingContext;
|
|||
|
pStation->Gen.pAdapterContext = pAdapterContext;
|
|||
|
pStation->Gen.ObjectType = (UCHAR)ObjectType;
|
|||
|
|
|||
|
//
|
|||
|
// The LLC objects must be referenced whenever they should be kept alive
|
|||
|
// over a long operation, that opens the spin locks (especially async
|
|||
|
// operations)
|
|||
|
// The first reference is for open/close
|
|||
|
//
|
|||
|
|
|||
|
ReferenceObject(pStation);
|
|||
|
|
|||
|
//
|
|||
|
// These values are common for SAP, direct (and DIX objects)
|
|||
|
//
|
|||
|
|
|||
|
pStation->Sap.OpenOptions = OpenOptions;
|
|||
|
pStation->Dix.ObjectAddress = ObjectAddress;
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
|||
|
|
|||
|
switch (pStation->Gen.ObjectType) {
|
|||
|
case LLC_SAP_OBJECT:
|
|||
|
|
|||
|
//
|
|||
|
// RLF 05/13/93
|
|||
|
//
|
|||
|
// don't allow multiple applications to open the same SAP. This is
|
|||
|
// incompatible with OS/2 DLC
|
|||
|
//
|
|||
|
|
|||
|
if (pAdapterContext->apSapBindings[ObjectAddress] == NULL) {
|
|||
|
ppListBase = (PVOID*)&(pAdapterContext->apSapBindings[ObjectAddress]);
|
|||
|
LlcMemCpy(&pStation->Sap.DefaultParameters,
|
|||
|
&DefaultParameters,
|
|||
|
sizeof(DefaultParameters)
|
|||
|
);
|
|||
|
|
|||
|
ALLOCATE_SPIN_LOCK(&pStation->Sap.FlowControlLock);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
FREE_MEMORY_FILE(pStation);
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
|||
|
|
|||
|
return DLC_STATUS_INVALID_SAP_VALUE;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case LLC_GROUP_SAP_OBJECT:
|
|||
|
ppListBase = (PVOID*)&(pAdapterContext->apSapBindings[ObjectAddress]);
|
|||
|
|
|||
|
//
|
|||
|
// All members of the same group/individual SAP muust have set
|
|||
|
// the same XID handling option
|
|||
|
//
|
|||
|
|
|||
|
if (pAdapterContext->apSapBindings[ObjectAddress] != NULL) {
|
|||
|
if ((OpenOptions & LLC_EXCLUSIVE_ACCESS)
|
|||
|
|| (pAdapterContext->apSapBindings[ObjectAddress]->OpenOptions
|
|||
|
& LLC_EXCLUSIVE_ACCESS)) {
|
|||
|
LlcStatus = DLC_STATUS_INVALID_SAP_VALUE;
|
|||
|
} else if ((pAdapterContext->apSapBindings[ObjectAddress]->OpenOptions &
|
|||
|
LLC_HANDLE_XID_COMMANDS) != (OpenOptions & LLC_HANDLE_XID_COMMANDS)) {
|
|||
|
LlcStatus = DLC_STATUS_INVALID_OPTION;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ALLOCATE_SPIN_LOCK(&pStation->Sap.FlowControlLock);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case LLC_DIRECT_OBJECT:
|
|||
|
ppListBase = (PVOID*)&pAdapterContext->pDirectStation;
|
|||
|
break;
|
|||
|
|
|||
|
case LLC_DIX_OBJECT:
|
|||
|
if (pAdapterContext->NdisMedium != NdisMedium802_3) {
|
|||
|
LlcStatus = DLC_STATUS_INVALID_STATION_ID;
|
|||
|
} else {
|
|||
|
ppListBase = (PVOID*)&(pAdapterContext->aDixStations[ObjectAddress % MAX_DIX_TABLE]);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
#if LLC_DBG
|
|||
|
default:
|
|||
|
LlcInvalidObjectType();
|
|||
|
break;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
if (LlcStatus == STATUS_SUCCESS) {
|
|||
|
pStation->Gen.pNext = *ppListBase;
|
|||
|
*phStation = *ppListBase = pStation;
|
|||
|
|
|||
|
pAdapterContext->ObjectCount++;
|
|||
|
} else {
|
|||
|
|
|||
|
FREE_MEMORY_FILE(pStation);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
|||
|
|
|||
|
if (LlcStatus == STATUS_SUCCESS
|
|||
|
&& pStation->Gen.ObjectType == LLC_DIRECT_OBJECT
|
|||
|
&& OpenOptions & DLC_RCV_MAC_FRAMES
|
|||
|
&& !(pAdapterContext->OpenOptions & DLC_RCV_MAC_FRAMES)) {
|
|||
|
|
|||
|
//
|
|||
|
// We enable the MAC frames, if they have once been enabled,
|
|||
|
// but they will never be disabled again. The receiving
|
|||
|
// of MAC frames is quite exceptional case, and it is
|
|||
|
// not really worth of it to maintain local and global
|
|||
|
// Ndis flag states just because of it
|
|||
|
//
|
|||
|
|
|||
|
PacketFilter = NDIS_PACKET_TYPE_DIRECTED
|
|||
|
| NDIS_PACKET_TYPE_MULTICAST
|
|||
|
| NDIS_PACKET_TYPE_FUNCTIONAL
|
|||
|
| NDIS_PACKET_TYPE_MAC_FRAME;
|
|||
|
|
|||
|
pAdapterContext->OpenOptions |= DLC_RCV_MAC_FRAMES;
|
|||
|
LlcStatus = SetNdisParameter(pAdapterContext,
|
|||
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|||
|
&PacketFilter,
|
|||
|
sizeof(PacketFilter)
|
|||
|
);
|
|||
|
}
|
|||
|
return LlcStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DLC_STATUS
|
|||
|
LlcCloseStation(
|
|||
|
IN PLLC_OBJECT pStation,
|
|||
|
IN PLLC_PACKET pCompletionPacket
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The primitive closes a direct, sap or link station object.
|
|||
|
All pending transmit commands are terminated.
|
|||
|
This primitive does not support graceful termination, but
|
|||
|
the upper level must wait the pending transmit commands, if
|
|||
|
it want to make a clean close (without deleting the transmit queue).
|
|||
|
|
|||
|
For a link station this primitive releases a disconnected link
|
|||
|
station or discards a remote connection request.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pStation - handle of a link, sap or direct station
|
|||
|
pCompletionPacket - returned context, when the command is complete
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DLC_STATUS
|
|||
|
Success - STATUS_SUCCESS
|
|||
|
Failure - DLC_STATUS_INVALID_PARAMETERS
|
|||
|
the SAP has still active link stations. All active link
|
|||
|
stations must be closed before sap can be closed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER_CONTEXT pAdapterContext = pStation->Gen.pAdapterContext;
|
|||
|
PBINDING_CONTEXT pOldBinding;
|
|||
|
PDATA_LINK* ppLink;
|
|||
|
PVOID* ppLinkListBase;
|
|||
|
PEVENT_PACKET pEvent;
|
|||
|
|
|||
|
if (pStation->Gen.ObjectType == LLC_LINK_OBJECT) {
|
|||
|
|
|||
|
//
|
|||
|
// The remote connection requests are routed through all
|
|||
|
// SAP station reqistered on a SAP until someone accepts
|
|||
|
// the connection request or it has been routed to all
|
|||
|
// clients having opened the sap station.
|
|||
|
//
|
|||
|
|
|||
|
if (pStation->Link.Flags & DLC_ACTIVE_REMOTE_CONNECT_REQUEST) {
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
|||
|
|
|||
|
pOldBinding = pStation->Gen.pLlcBinding;
|
|||
|
if (pStation->Link.pSap->Gen.pNext != NULL) {
|
|||
|
pStation->Gen.pLlcBinding = pStation->Link.pSap->Gen.pNext->Gen.pLlcBinding;
|
|||
|
}
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
|||
|
|
|||
|
//
|
|||
|
// Complete the close command immediately, if
|
|||
|
// the connect request was redirected to another
|
|||
|
// SAP station
|
|||
|
//
|
|||
|
|
|||
|
if (pStation->Gen.pLlcBinding != pOldBinding) {
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
|||
|
|
|||
|
pEvent = ALLOCATE_PACKET_LLC_PKT(pAdapterContext->hPacketPool);
|
|||
|
|
|||
|
if (pEvent != NULL) {
|
|||
|
LlcInsertTailList(&pAdapterContext->QueueEvents, pEvent);
|
|||
|
pEvent->pBinding = pStation->Gen.pLlcBinding;
|
|||
|
pEvent->hClientHandle = pStation->Link.pSap->Gen.hClientHandle;
|
|||
|
pEvent->Event = LLC_STATUS_CHANGE_ON_SAP;
|
|||
|
pEvent->pEventInformation = &pStation->Link.DlcStatus;
|
|||
|
pEvent->SecondaryInfo = INDICATE_CONNECT_REQUEST;
|
|||
|
}
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
|||
|
|
|||
|
if (pEvent != NULL) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Nobody accepted this connect request, we must discard it.
|
|||
|
//
|
|||
|
|
|||
|
RunInterlockedStateMachineCommand((PDATA_LINK)pStation, SET_ADM);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
|||
|
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
|||
|
|
|||
|
DLC_TRACE('C');
|
|||
|
|
|||
|
switch (pStation->Gen.ObjectType) {
|
|||
|
case LLC_DIRECT_OBJECT:
|
|||
|
|
|||
|
//
|
|||
|
// This Direct must be in the linked list of Directs (having
|
|||
|
// the same source Direct).
|
|||
|
//
|
|||
|
|
|||
|
ppLinkListBase = (PVOID*)&pAdapterContext->pDirectStation;
|
|||
|
|
|||
|
DLC_TRACE('b');
|
|||
|
break;
|
|||
|
|
|||
|
case LLC_DIX_OBJECT:
|
|||
|
|
|||
|
//
|
|||
|
// This Direct must be in the linked list of Directs (having
|
|||
|
// the same source Direct).
|
|||
|
//
|
|||
|
|
|||
|
ppLinkListBase = (PVOID*)&pAdapterContext->aDixStations[pStation->Dix.ObjectAddress % MAX_DIX_TABLE];
|
|||
|
DLC_TRACE('a');
|
|||
|
break;
|
|||
|
|
|||
|
case LLC_SAP_OBJECT:
|
|||
|
|
|||
|
#if LLC_DBG
|
|||
|
if (pStation->Sap.pActiveLinks != NULL) {
|
|||
|
DbgPrint("Closing SAP before link stations!!!\n");
|
|||
|
DbgBreakPoint();
|
|||
|
|
|||
|
//
|
|||
|
// Open the spin locks and return thge error status
|
|||
|
//
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
|||
|
|
|||
|
return DLC_STATUS_LINK_STATIONS_OPEN;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
DLC_TRACE('d');
|
|||
|
|
|||
|
case LLC_GROUP_SAP_OBJECT:
|
|||
|
|
|||
|
//
|
|||
|
// This SAP must be in the linked list of SAPs (having
|
|||
|
// the same source SAP).
|
|||
|
//
|
|||
|
|
|||
|
ppLinkListBase = (PVOID*)&pAdapterContext->apSapBindings[pStation->Sap.SourceSap];
|
|||
|
|
|||
|
DEALLOCATE_SPIN_LOCK(&pStation->Sap.FlowControlLock);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case LLC_LINK_OBJECT:
|
|||
|
|
|||
|
//
|
|||
|
// Only a disconnected link station can be deactivated.
|
|||
|
// If this fails, then we must disconnect the link station,
|
|||
|
// if it is not already disconnected.
|
|||
|
//
|
|||
|
|
|||
|
if (RunStateMachineCommand((PDATA_LINK)pStation, DEACTIVATE_LS) != STATUS_SUCCESS
|
|||
|
&& pStation->Link.State != DISCONNECTING) {
|
|||
|
|
|||
|
//
|
|||
|
// We must disconnect the link station immediately.
|
|||
|
// We don't care if we are at the moment in
|
|||
|
// a checkpoint state, that would delay the disconnection
|
|||
|
// until the other side has acknowledged it.
|
|||
|
// The link station must be killed now!
|
|||
|
//
|
|||
|
|
|||
|
SendLlcFrame((PDATA_LINK)pStation, DLC_DISC_TOKEN | 1);
|
|||
|
DisableSendProcess((PDATA_LINK)pStation);
|
|||
|
}
|
|||
|
pStation->Link.State = LINK_CLOSED;
|
|||
|
ppLinkListBase = (PVOID *)&pStation->Link.pSap->pActiveLinks;
|
|||
|
ppLink = SearchLinkAddress(pAdapterContext, pStation->Link.LinkAddr);
|
|||
|
*ppLink = pStation->Link.pNextNode;
|
|||
|
|
|||
|
TerminateTimer(pAdapterContext, &pStation->Link.T1);
|
|||
|
TerminateTimer(pAdapterContext, &pStation->Link.T2);
|
|||
|
TerminateTimer(pAdapterContext, &pStation->Link.Ti);
|
|||
|
DLC_TRACE('c');
|
|||
|
break;
|
|||
|
|
|||
|
#if LLC_DBG
|
|||
|
default:
|
|||
|
LlcInvalidObjectType();
|
|||
|
break;
|
|||
|
#endif
|
|||
|
}
|
|||
|
RemoveFromLinkList(ppLinkListBase, pStation);
|
|||
|
|
|||
|
//
|
|||
|
// Queue the asynchronous close command. Group sap and
|
|||
|
// disabling of non-existing link station may use
|
|||
|
// a null packet, because those commands are executed
|
|||
|
// synchronously (they cannot have pending packets)
|
|||
|
//
|
|||
|
|
|||
|
if (pCompletionPacket != NULL) {
|
|||
|
AllocateCompletionPacket(pStation, LLC_CLOSE_COMPLETION, pCompletionPacket);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// OK. Everything has been processed =>
|
|||
|
// now we can decrement the object counter.
|
|||
|
//
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
|||
|
|
|||
|
//
|
|||
|
// Delete the object NOW, if this was the last reference to it
|
|||
|
//
|
|||
|
|
|||
|
LlcDereferenceObject(pStation);
|
|||
|
|
|||
|
return STATUS_PENDING;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
CompleteClose(
|
|||
|
IN PLLC_OBJECT pLlcObject,
|
|||
|
IN UINT CancelStatus
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Procedure cancel all pending commands of llc object and
|
|||
|
deletes the object.
|
|||
|
The procedure returns a pending status as far the object
|
|||
|
has pending transmits in NDIS.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLlcObject - LLC object
|
|||
|
CancelStatus - the status returned in the cancelled (completed) commands
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER_CONTEXT pAdapterContext = pLlcObject->Gen.pAdapterContext;
|
|||
|
UINT Status;
|
|||
|
|
|||
|
#if DBG
|
|||
|
PDLC_FILE_CONTEXT pFileContext = (PDLC_FILE_CONTEXT)(pLlcObject->Gen.pLlcBinding->hClientContext);
|
|||
|
#endif
|
|||
|
|
|||
|
if (pLlcObject->Gen.ReferenceCount != 0) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Cancel the queue transmit commands
|
|||
|
//
|
|||
|
|
|||
|
CancelTransmitCommands(pLlcObject, CancelStatus);
|
|||
|
|
|||
|
//
|
|||
|
// Queue also all commands queued in the link stations
|
|||
|
// (actually only LlcConnect and LlcDisconnect),
|
|||
|
// Note: the queue command eats the list of completion packets.
|
|||
|
//
|
|||
|
|
|||
|
while (pLlcObject->Gen.pCompletionPackets != NULL) {
|
|||
|
Status = CancelStatus;
|
|||
|
if (pLlcObject->Gen.pCompletionPackets->Data.Completion.CompletedCommand == LLC_CLOSE_COMPLETION) {
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
QueueCommandCompletion(pLlcObject,
|
|||
|
(UINT)pLlcObject->Gen.pCompletionPackets->Data.Completion.CompletedCommand,
|
|||
|
Status
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// release link station specific resources
|
|||
|
//
|
|||
|
|
|||
|
if (pLlcObject->Gen.ObjectType == LLC_LINK_OBJECT) {
|
|||
|
|
|||
|
//
|
|||
|
// The link may have been closed because of an error
|
|||
|
// or timeout (eg. somebody has turned the power off in the
|
|||
|
// other side). We must complete all pending transmits with
|
|||
|
// an error. We assume, that the link has not any more
|
|||
|
// any packets in NDIS queues, but is does not matter,
|
|||
|
// because NDIS packets of a link station will never be
|
|||
|
// directly indicated to the user (they may not exist any
|
|||
|
// more). Thus nothing fatal can happen, if we simply
|
|||
|
// complete all packets and return them to the main
|
|||
|
// packet storage.
|
|||
|
//
|
|||
|
|
|||
|
DEALLOCATE_PACKET_LLC_LNK(pAdapterContext->hLinkPool, pLlcObject);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
FREE_MEMORY_FILE(pLlcObject);
|
|||
|
|
|||
|
}
|
|||
|
pAdapterContext->ObjectCount--;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
CancelTransmitCommands(
|
|||
|
IN PLLC_OBJECT pLlcObject,
|
|||
|
IN UINT Status
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Procedure removes the transmit commands of the given LLC client
|
|||
|
from the transmit queue. This cannot cancel those dir/sap transmit
|
|||
|
already queued in NDIS, but the caller must first wait that the
|
|||
|
object has no commands in the NDIS queue.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLlcObject - LLC object
|
|||
|
Status - status to set in cancelled transmit commands
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER_CONTEXT pAdapterContext = pLlcObject->Gen.pAdapterContext;
|
|||
|
|
|||
|
//
|
|||
|
// We can (and must) cancel all pending transmits on a link
|
|||
|
// without any global locks, when the station has first
|
|||
|
// been removed from all global data structures,
|
|||
|
//
|
|||
|
|
|||
|
if (pLlcObject->Gen.ObjectType == LLC_LINK_OBJECT) {
|
|||
|
CancelTransmitsInQueue(pLlcObject,
|
|||
|
Status,
|
|||
|
&((PDATA_LINK)pLlcObject)->SendQueue.ListHead,
|
|||
|
NULL
|
|||
|
);
|
|||
|
CancelTransmitsInQueue(pLlcObject,
|
|||
|
Status,
|
|||
|
&((PDATA_LINK)pLlcObject)->SentQueue,
|
|||
|
NULL
|
|||
|
);
|
|||
|
StopSendProcess(pAdapterContext, (PDATA_LINK)pLlcObject);
|
|||
|
|
|||
|
//
|
|||
|
// We cannot leave any S- commands with a reference to the
|
|||
|
// link lan header.
|
|||
|
//
|
|||
|
|
|||
|
CancelTransmitsInQueue(pLlcObject,
|
|||
|
Status,
|
|||
|
&pAdapterContext->QueueExpidited.ListHead,
|
|||
|
&pAdapterContext->QueueExpidited
|
|||
|
);
|
|||
|
} else {
|
|||
|
CancelTransmitsInQueue(pLlcObject,
|
|||
|
Status,
|
|||
|
&pAdapterContext->QueueDirAndU.ListHead,
|
|||
|
&pAdapterContext->QueueDirAndU
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
CancelTransmitsInQueue(
|
|||
|
IN PLLC_OBJECT pLlcObject,
|
|||
|
IN UINT Status,
|
|||
|
IN PLIST_ENTRY pQueue,
|
|||
|
IN PLLC_QUEUE pLlcQueue OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Procedure removes the transmit commands of the given LLC client
|
|||
|
from the transmit queue. This cannot cancel those dir/sap transmit
|
|||
|
already queued in NDIS, but the caller must first wait that the
|
|||
|
object has no commands in the NDIS queue.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLlcObject - LLC object
|
|||
|
Status - the status returned by the completed transmit commands
|
|||
|
pQueue - a data links transmit queue
|
|||
|
pLlcQueue - an optional LLC queue, that is disconnected from the send
|
|||
|
task if the subqueue becomes empty.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PLLC_PACKET pPacket;
|
|||
|
PLLC_PACKET pNextPacket;
|
|||
|
PADAPTER_CONTEXT pAdapterContext = pLlcObject->Gen.pAdapterContext;
|
|||
|
|
|||
|
//
|
|||
|
// Cancel all pending transmit commands in LLC queues,
|
|||
|
// check first, if the transmit queue is empty.
|
|||
|
//
|
|||
|
|
|||
|
if (IsListEmpty(pQueue)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for (pPacket = (PLLC_PACKET)pQueue->Flink; pPacket != (PLLC_PACKET)pQueue; pPacket = pNextPacket) {
|
|||
|
pNextPacket = pPacket->pNext;
|
|||
|
|
|||
|
//
|
|||
|
// Complete the packet only if it has a correct binding handle
|
|||
|
// and it belongs the given client object. Note: if binding
|
|||
|
// handle is null, then client object handle may be garbage!
|
|||
|
//
|
|||
|
|
|||
|
if (pPacket->CompletionType > LLC_MAX_RESPONSE_PACKET
|
|||
|
&& pPacket->Data.Xmit.pLlcObject == pLlcObject) {
|
|||
|
LlcRemoveEntryList(pPacket);
|
|||
|
|
|||
|
//
|
|||
|
// We MUST NOT cancel those transmit commands, that are
|
|||
|
// still in the NDIS queue!!!! The command completion would
|
|||
|
// make the MDLs in NDIS packet invalid => system would crash.
|
|||
|
//
|
|||
|
|
|||
|
if (((pPacket->CompletionType) & LLC_I_PACKET_PENDING_NDIS) == 0) {
|
|||
|
if (pPacket->pBinding != NULL) {
|
|||
|
LlcInsertTailList(&pAdapterContext->QueueCommands, pPacket);
|
|||
|
pPacket->Data.Completion.CompletedCommand = LLC_SEND_COMPLETION;
|
|||
|
pPacket->Data.Completion.Status = Status;
|
|||
|
pPacket->Data.Completion.hClientHandle = pLlcObject->Gen.hClientHandle;
|
|||
|
} else {
|
|||
|
|
|||
|
DEALLOCATE_PACKET_LLC_PKT(pAdapterContext->hPacketPool, pPacket);
|
|||
|
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The I-frames must be discarded by the link protocol, because
|
|||
|
// the link is now dead, and we will complete them immediately
|
|||
|
// when NdisSend the completes.
|
|||
|
//
|
|||
|
|
|||
|
pPacket->CompletionType &= ~LLC_I_PACKET_UNACKNOWLEDGED;
|
|||
|
pPacket->Data.Completion.CompletedCommand = LLC_SEND_COMPLETION;
|
|||
|
pPacket->Data.Completion.Status = Status;
|
|||
|
pPacket->Data.Completion.hClientHandle = pLlcObject->Gen.hClientHandle;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Disconnect the list from the send task, if is now empty,
|
|||
|
// We don't use this check with the I- frame queues
|
|||
|
// (StopSendProcess does the same thing for them).
|
|||
|
//
|
|||
|
|
|||
|
if (pLlcQueue != NULL
|
|||
|
&& IsListEmpty(&pLlcQueue->ListHead)
|
|||
|
&& pLlcQueue->ListEntry.Flink != NULL) {
|
|||
|
LlcRemoveEntryList(&pLlcQueue->ListEntry);
|
|||
|
pLlcQueue->ListEntry.Flink = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Procedure sets new open options (receive mask) for a direct station.
|
|||
|
// The MAC frames must have been enabled, when the direct
|
|||
|
// object was opened on data link.
|
|||
|
// This is called whenever DLC receive command is issued for direct station.
|
|||
|
//
|
|||
|
VOID
|
|||
|
LlcSetDirectOpenOptions(
|
|||
|
IN PLLC_OBJECT pDirect,
|
|||
|
IN USHORT OpenOptions
|
|||
|
)
|
|||
|
{
|
|||
|
pDirect->Dir.OpenOptions = OpenOptions;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
CompleteObjectDelete(
|
|||
|
IN PLLC_OBJECT pStation
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The function completes the delete operation for a llc object.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pStation - link, sap or direct station handle
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER_CONTEXT pAdapterContext = pStation->Gen.pAdapterContext;
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
|||
|
|
|||
|
if (pStation->Gen.ReferenceCount == 0) {
|
|||
|
CompletePendingLlcCommand(pStation);
|
|||
|
BackgroundProcessAndUnlock(pAdapterContext);
|
|||
|
} else {
|
|||
|
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
CompletePendingLlcCommand(
|
|||
|
PLLC_OBJECT pLlcObject
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The routines cleans up all commands and event of a llc object
|
|||
|
from the the data link driver.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLlObject - a data link object handle (opeque pointer)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// The reference count is zero only if the object is deleted,
|
|||
|
// otherwise this is just a reset for a link station.
|
|||
|
//
|
|||
|
|
|||
|
if (pLlcObject->Gen.ReferenceCount == 0) {
|
|||
|
CompleteClose(pLlcObject, DLC_STATUS_CANCELLED_BY_SYSTEM_ACTION);
|
|||
|
} else {
|
|||
|
CancelTransmitCommands(pLlcObject, DLC_STATUS_LINK_NOT_TRANSMITTING);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
LlcDereferenceObject(
|
|||
|
IN PVOID pStation
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The function dereferences any LLC object.
|
|||
|
THIS ROUTINE MUST BE CALLED ALL SPIN LOCKS UNLOCKED,
|
|||
|
BECAUSE IT MAY CALL BACK !!!!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pStation - link, sap or direct station handle
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DLC_TRACE('L');
|
|||
|
DLC_TRACE((UCHAR)((PLLC_OBJECT)pStation)->Gen.ReferenceCount - 1);
|
|||
|
|
|||
|
if (InterlockedDecrement((PLONG)&(((PLLC_OBJECT)(pStation))->Gen.ReferenceCount)) == 0) {
|
|||
|
CompleteObjectDelete(pStation);
|
|||
|
}
|
|||
|
|
|||
|
/* pStation might have been freed by now
|
|||
|
DLC_TRACE('L');
|
|||
|
DLC_TRACE((UCHAR)((PLLC_OBJECT)pStation)->Gen.ReferenceCount); */
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
LlcReferenceObject(
|
|||
|
IN PVOID pStation
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The function references any LLC object. The non-zero
|
|||
|
reference counter keeps LLC objects alive.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pStation - link, sap or direct station handle
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
InterlockedIncrement((PLONG)&(((PLLC_OBJECT)pStation)->Gen.ReferenceCount));
|
|||
|
DLC_TRACE('M');
|
|||
|
DLC_TRACE((UCHAR)((PLLC_OBJECT)pStation)->Gen.ReferenceCount);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if !DLC_AND_LLC
|
|||
|
|
|||
|
//
|
|||
|
// the following routines can be used as macros if DLC and LLC live in the same
|
|||
|
// driver and the one knows about the other's structures
|
|||
|
//
|
|||
|
|
|||
|
UINT
|
|||
|
LlcGetReceivedLanHeaderLength(
|
|||
|
IN PVOID pBinding
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the length of the LAN header of the frame last received from NDIS.
|
|||
|
The size is 14 for all Ethernet types except direct Ethernet frames, and
|
|||
|
whatever we stored in the RcvLanHeaderLength field of the ADAPTER_CONTEXT
|
|||
|
for Token Ring (can contain source routing)
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pBinding - pointer to BINDING_CONTEXT structure describing adapter
|
|||
|
on which frame of interest was received
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
UINT
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return (((PBINDING_CONTEXT)pBinding)->pAdapterContext->NdisMedium == NdisMedium802_3)
|
|||
|
? (((PBINDING_CONTEXT)pBinding)->pAdapterContext->FrameType == LLC_DIRECT_ETHERNET_TYPE)
|
|||
|
? 12
|
|||
|
: 14
|
|||
|
: ((PBINDING_CONTEXT)pBinding)->pAdapterContext->RcvLanHeaderLength;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
USHORT
|
|||
|
LlcGetEthernetType(
|
|||
|
IN PVOID hContext
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the Ethernet type set in the adapter context
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hContext - handle of/pointer to BINDING_CONTEXT structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
USHORT
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return ((PBINDING_CONTEXT)hContext)->pAdapterContext->EthernetType;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
UINT
|
|||
|
LlcGetCommittedSpace(
|
|||
|
IN PVOID hLink
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the amount of committed buffer space
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hLink -
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
UINT
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return ((PDATA_LINK)hLink)->BufferCommitment;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|