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.
1870 lines
51 KiB
1870 lines
51 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
Copyright (c) 1991 Nokia Data Systems AB
|
|
|
|
Module Name:
|
|
|
|
dlcreq.c
|
|
|
|
Abstract:
|
|
|
|
This module handles the miscellaneous DLC requests (set & query information)
|
|
|
|
Contents:
|
|
DlcBufferFree
|
|
DlcBufferGet
|
|
DlcBufferCreate
|
|
DlcConnectStation
|
|
DlcFlowControl
|
|
ResetLocalBusyBufferStates
|
|
DlcReallocate
|
|
DlcReset
|
|
DirSetExceptionFlags
|
|
CompleteAsyncCommand
|
|
GetLinkStation
|
|
GetSapStation
|
|
GetStation
|
|
DlcReadCancel
|
|
DirOpenAdapter
|
|
DirCloseAdapter
|
|
CompleteDirCloseAdapter
|
|
DlcCompleteCommand
|
|
|
|
Author:
|
|
|
|
Antti Saarenheimo 22-Jul-1991 (o-anttis)
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <dlc.h>
|
|
#include "dlcdebug.h"
|
|
|
|
#if 0
|
|
|
|
//
|
|
// if DLC and LLC share the same driver then we can use macros to access fields
|
|
// in the BINDING_CONTEXT and ADAPTER_CONTEXT structures
|
|
//
|
|
|
|
#if DLC_AND_LLC
|
|
#ifndef i386
|
|
#define LLC_PRIVATE_PROTOTYPES
|
|
#endif
|
|
#include "llcdef.h"
|
|
#include "llctyp.h"
|
|
#include "llcapi.h"
|
|
#endif
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DlcBufferFree(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure simply releases the given user buffers.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC address object
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
DLC_STATUS_INADEQUATE_BUFFERS - buffer pool does not exist
|
|
DLC_STATUS_INVALID_STATION_ID -
|
|
DLC_STATUS_INVALID_BUFFER_LENGTH -
|
|
|
|
NOTE!!! BUFFER.FREE does not return error, if the
|
|
given buffer is invalid, or released twice!!!
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
if (!pFileContext->hBufferPool) {
|
|
return DLC_STATUS_INADEQUATE_BUFFERS;
|
|
}
|
|
|
|
//
|
|
// The parameter list is a DLC desriptor array.
|
|
// Get the number of descriptor elements in the array.
|
|
//
|
|
|
|
if (InputBufferLength != (sizeof(NT_DLC_BUFFER_FREE_PARMS)
|
|
- sizeof(LLC_TRANSMIT_DESCRIPTOR)
|
|
+ pDlcParms->BufferFree.BufferCount
|
|
* sizeof(LLC_TRANSMIT_DESCRIPTOR))) {
|
|
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
|
}
|
|
|
|
//
|
|
// We refernce the buffer pool, because otherwise it may disappear
|
|
// immeadiately after DLC_LEAVE (when the adapter is closed)
|
|
//
|
|
|
|
ReferenceBufferPool(pFileContext);
|
|
|
|
//
|
|
// Don't try to allocate 0 buffers, it will fail.
|
|
//
|
|
|
|
if (pDlcParms->BufferFree.BufferCount) {
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
RELEASE_DRIVER_LOCK();
|
|
|
|
status = BufferPoolDeallocate(pFileContext->hBufferPool,
|
|
pDlcParms->BufferFree.BufferCount,
|
|
pDlcParms->BufferFree.DlcBuffer
|
|
);
|
|
|
|
ACQUIRE_DRIVER_LOCK();
|
|
|
|
ENTER_DLC(pFileContext);
|
|
|
|
//
|
|
// Reset the local busy states, if there is now enough
|
|
// buffers the receive the expected stuff.
|
|
//
|
|
|
|
if (!IsListEmpty(&pFileContext->FlowControlQueue)
|
|
&& BufGetUncommittedSpace(pFileContext->hBufferPool) >= 0) {
|
|
ResetLocalBusyBufferStates(pFileContext);
|
|
}
|
|
|
|
#if LLC_DBG
|
|
cFramesReleased++;
|
|
#endif
|
|
|
|
}
|
|
|
|
pDlcParms->BufferFree.cBuffersLeft = (USHORT)BufferPoolCount(pFileContext->hBufferPool);
|
|
|
|
DereferenceBufferPool(pFileContext);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DlcBufferGet(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure allocates the requested number or size of DLC buffers
|
|
and returns them back to user in a single entry link list..
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
UINT SegmentSize;
|
|
UINT SizeIndex;
|
|
UINT BufferSize;
|
|
UINT PrevBufferSize;
|
|
UINT cBuffersToGet;
|
|
PDLC_BUFFER_HEADER pBufferHeader = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
if (pFileContext->hBufferPool == NULL) {
|
|
return DLC_STATUS_INADEQUATE_BUFFERS;
|
|
}
|
|
|
|
//
|
|
// If the segment size is 0, then we return the optimal mix
|
|
// of buffer for the requested size. Non null buffer count defines
|
|
// how many buffers having the requested size is returned.
|
|
//
|
|
|
|
cBuffersToGet = pDlcParms->BufferGet.cBuffersToGet;
|
|
|
|
/*******************************************************************************
|
|
|
|
#if PAGE_SIZE == 8192
|
|
if (cBuffersToGet == 0) {
|
|
cBuffersToGet = 1;
|
|
SegmentSize = pDlcParms->BufferGet.cbBufferSize;
|
|
SizeIndex = (UINT)(-1);
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 256) {
|
|
SegmentSize = 256 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 5;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 512) {
|
|
SegmentSize = 512 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 4;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 1024) {
|
|
SegmentSize = 1024 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 3;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 2048) {
|
|
SegmentSize = 2048 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 2;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 4096) {
|
|
SegmentSize = 4096 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 1;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 8192) {
|
|
SegmentSize = 8192 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 0;
|
|
} else {
|
|
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
|
}
|
|
#elif PAGE_SIZE == 4096
|
|
if (cBuffersToGet == 0) {
|
|
cBuffersToGet = 1;
|
|
SegmentSize = pDlcParms->BufferGet.cbBufferSize;
|
|
SizeIndex = (UINT)(-1);
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 256) {
|
|
SegmentSize = 256 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 4;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 512) {
|
|
SegmentSize = 512 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 3;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 1024) {
|
|
SegmentSize = 1024 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 2;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 2048) {
|
|
SegmentSize = 2048 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 1;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 4096) {
|
|
SegmentSize = 4096 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 0;
|
|
} else {
|
|
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
|
}
|
|
#else
|
|
#error "Target machine page size not 4096 or 8192"
|
|
#endif
|
|
|
|
*******************************************************************************/
|
|
|
|
#if defined(ALPHA)
|
|
if (cBuffersToGet == 0) {
|
|
cBuffersToGet = 1;
|
|
SegmentSize = pDlcParms->BufferGet.cbBufferSize;
|
|
SizeIndex = (UINT)(-1);
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 256) {
|
|
SegmentSize = 256 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 5;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 512) {
|
|
SegmentSize = 512 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 4;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 1024) {
|
|
SegmentSize = 1024 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 3;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 2048) {
|
|
SegmentSize = 2048 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 2;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 4096) {
|
|
SegmentSize = 4096 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 1;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 8192) {
|
|
SegmentSize = 8192 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 0;
|
|
} else {
|
|
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
|
}
|
|
#else
|
|
if (cBuffersToGet == 0) {
|
|
cBuffersToGet = 1;
|
|
SegmentSize = pDlcParms->BufferGet.cbBufferSize;
|
|
SizeIndex = (UINT)(-1);
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 256) {
|
|
SegmentSize = 256 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 4;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 512) {
|
|
SegmentSize = 512 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 3;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 1024) {
|
|
SegmentSize = 1024 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 2;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 2048) {
|
|
SegmentSize = 2048 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 1;
|
|
} else if (pDlcParms->BufferGet.cbBufferSize <= 4096) {
|
|
SegmentSize = 4096 - sizeof(NEXT_DLC_SEGMENT);
|
|
SizeIndex = 0;
|
|
} else {
|
|
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// We refernce the buffer pool, because otherwise it may disappear
|
|
// immeadiately after DLC_LEAVE (when the adapter is closed)
|
|
//
|
|
|
|
ReferenceBufferPool(pFileContext);
|
|
|
|
//
|
|
// We don't need to initialize the LAN and DLC header sizes
|
|
// in the buffer header and we allocate the requested
|
|
// frame as a single buffer.
|
|
//
|
|
|
|
BufferSize = SegmentSize * cBuffersToGet;
|
|
if (BufferSize != 0) {
|
|
|
|
pBufferHeader = NULL;
|
|
PrevBufferSize = 0;
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
do {
|
|
|
|
//
|
|
// We must again do this interlocked to avoid the buffer
|
|
// pool to be deleted while we are allocating buffers.
|
|
//
|
|
|
|
Status = BufferPoolAllocate(
|
|
#if DBG
|
|
pFileContext,
|
|
#endif
|
|
(PDLC_BUFFER_POOL)pFileContext->hBufferPool,
|
|
BufferSize,
|
|
0, // FrameHeaderSize,
|
|
0, // UserDataSize,
|
|
0, // frame length
|
|
SizeIndex, // fixed segment size set
|
|
&pBufferHeader,
|
|
&BufferSize
|
|
);
|
|
|
|
#if DBG
|
|
BufferPoolExpand(pFileContext, (PDLC_BUFFER_POOL)pFileContext->hBufferPool);
|
|
#else
|
|
BufferPoolExpand((PDLC_BUFFER_POOL)pFileContext->hBufferPool);
|
|
#endif
|
|
|
|
//
|
|
// Don't try to expand buffer pool any more, if it doesn't help!
|
|
//
|
|
|
|
if (BufferSize == PrevBufferSize) {
|
|
break;
|
|
}
|
|
PrevBufferSize = BufferSize;
|
|
|
|
} while (Status == DLC_STATUS_EXPAND_BUFFER_POOL);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
|
|
if (pBufferHeader != NULL) {
|
|
pBufferHeader->FrameBuffer.BufferState = BUF_USER;
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
pDlcParms->BufferGet.pFirstBuffer = (PLLC_XMIT_BUFFER)
|
|
((PUCHAR)pBufferHeader->FrameBuffer.pParent->Header.pLocalVa +
|
|
MIN_DLC_BUFFER_SEGMENT * pBufferHeader->FrameBuffer.Index);
|
|
} else {
|
|
BufferPoolDeallocateList(pFileContext->hBufferPool, pBufferHeader);
|
|
}
|
|
}
|
|
|
|
pDlcParms->BufferGet.cBuffersLeft = (USHORT)BufferPoolCount(pFileContext->hBufferPool);
|
|
|
|
DereferenceBufferPool(pFileContext);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DlcBufferCreate(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure creates a new buffer pool and allocates the initial
|
|
space for it.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
Success - STATUS_SUCCESS
|
|
Failure - DLC_STATUS_DUPLICATE_COMMAND
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PVOID newBufferAddress;
|
|
ULONG newBufferSize;
|
|
PVOID hExternalBufferPool;
|
|
PVOID hBufferPool;
|
|
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
//
|
|
// if we already have a buffer pool defined for this handle, fail the
|
|
// request
|
|
//
|
|
|
|
if (pFileContext->hBufferPool) {
|
|
return DLC_STATUS_DUPLICATE_COMMAND;
|
|
}
|
|
|
|
hExternalBufferPool = pFileContext->hExternalBufferPool;
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
#if DBG
|
|
status = BufferPoolCreate(pFileContext,
|
|
#else
|
|
status = BufferPoolCreate(
|
|
#endif
|
|
pDlcParms->BufferCreate.pBuffer,
|
|
pDlcParms->BufferCreate.cbBufferSize,
|
|
pDlcParms->BufferCreate.cbMinimumSizeThreshold,
|
|
&hExternalBufferPool,
|
|
&newBufferAddress,
|
|
&newBufferSize
|
|
);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
pFileContext->hExternalBufferPool = hExternalBufferPool;
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// The reference count keeps the buffer pool alive
|
|
// when it is used (and simultaneously deleted by another
|
|
// thread)
|
|
//
|
|
|
|
pFileContext->BufferPoolReferenceCount = 1;
|
|
hBufferPool = pFileContext->hBufferPool;
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
status = BufferPoolReference(hExternalBufferPool,
|
|
&hBufferPool
|
|
);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
pFileContext->hBufferPool = hBufferPool;
|
|
pDlcParms->BufferCreate.hBufferPool = pFileContext->hExternalBufferPool;
|
|
}
|
|
|
|
// ENTER_DLC(pFileContext);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DlcConnectStation(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure connects an local link station to a remote node
|
|
or accepts a remote connection request.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_OBJECT pLinkStation;
|
|
NTSTATUS Status;
|
|
PUCHAR pSourceRouting = NULL;
|
|
PDLC_COMMAND pPacket;
|
|
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
//
|
|
// Procedure checks the sap and link station ids and
|
|
// returns the requested link station.
|
|
// The error status indicates a wrong sap or station id.
|
|
//
|
|
|
|
Status = GetLinkStation(pFileContext,
|
|
pDlcParms->Async.Parms.DlcConnectStation.StationId,
|
|
&pLinkStation
|
|
);
|
|
if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
pPacket = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
|
|
|
|
if (pPacket == NULL) {
|
|
return DLC_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
pPacket->pIrp = pIrp;
|
|
|
|
//
|
|
// IBM LAN Tech. Ref p 3-48 (DLC.CONNECT.STATION) states that ROUTING_ADDR
|
|
// field is ignored if the link was created due to receipt of a SABME from
|
|
// the remote station, EVEN IF THE ADDRESS IS NON-ZERO
|
|
//
|
|
|
|
if (pDlcParms->Async.Parms.DlcConnectStation.RoutingInformationLength != 0) {
|
|
pSourceRouting = pDlcParms->Async.Parms.DlcConnectStation.aRoutingInformation;
|
|
}
|
|
pLinkStation->PendingLlcRequests++;
|
|
ReferenceLlcObject(pLinkStation);
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
//
|
|
// LlcConnect returns the maximum information field,
|
|
// through the tr bridges!
|
|
//
|
|
|
|
LlcConnectStation(pLinkStation->hLlcObject,
|
|
(PLLC_PACKET)pPacket,
|
|
pSourceRouting,
|
|
&pLinkStation->u.Link.MaxInfoFieldLength
|
|
);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
|
|
DereferenceLlcObject(pLinkStation);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DlcFlowControl(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure sets or resets the loacl busy state on the given link station
|
|
or on all link stations of a sap station.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
Success - STATUS_SUCCESS
|
|
Failure - DLC_STATUS_NO_MEMORY
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PDLC_OBJECT pDlcObject;
|
|
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
//
|
|
// Procedure checks the sap and link station ids and
|
|
// returns the requested link station.
|
|
// The error status indicates a wrong sap or station id.
|
|
//
|
|
|
|
Status = GetStation(pFileContext,
|
|
pDlcParms->DlcFlowControl.StationId,
|
|
&pDlcObject
|
|
);
|
|
if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// We will queue all reset local busy buffer commands
|
|
// given to the link stations
|
|
//
|
|
|
|
if (((pDlcParms->DlcFlowControl.FlowControlOption & LLC_RESET_LOCAL_BUSY_BUFFER) == LLC_RESET_LOCAL_BUSY_BUFFER)
|
|
&& (pDlcObject->Type == DLC_LINK_OBJECT)) {
|
|
|
|
PDLC_RESET_LOCAL_BUSY_CMD pClearCmd;
|
|
|
|
pClearCmd = (PDLC_RESET_LOCAL_BUSY_CMD)ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
|
|
|
|
if (pClearCmd == NULL) {
|
|
return DLC_STATUS_NO_MEMORY;
|
|
}
|
|
pClearCmd->StationId = pDlcParms->DlcFlowControl.StationId;
|
|
pClearCmd->RequiredBufferSpace = 0;
|
|
LlcInsertTailList(&pFileContext->FlowControlQueue, pClearCmd);
|
|
ResetLocalBusyBufferStates(pFileContext);
|
|
} else {
|
|
ReferenceLlcObject(pDlcObject);
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
Status = LlcFlowControl(pDlcObject->hLlcObject,
|
|
pDlcParms->DlcFlowControl.FlowControlOption
|
|
);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
|
|
DereferenceLlcObject(pDlcObject);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
ResetLocalBusyBufferStates(
|
|
IN PDLC_FILE_CONTEXT pFileContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure executes the pending busy state resets when there is
|
|
enough memory in the buffer pool to receive the expected data.
|
|
|
|
Arguments:
|
|
|
|
pFileContext - DLC adapter context
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PDLC_OBJECT pDlcObject;
|
|
PDLC_RESET_LOCAL_BUSY_CMD pClearCmd;
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
//
|
|
// We cannot reset anything, if the buffer pool is not yet
|
|
// defined.
|
|
//
|
|
|
|
if (pFileContext->hBufferPool == NULL) {
|
|
return;
|
|
}
|
|
|
|
ReferenceBufferPool(pFileContext);
|
|
|
|
while (!IsListEmpty(&pFileContext->FlowControlQueue)) {
|
|
pClearCmd = LlcRemoveHeadList(&pFileContext->FlowControlQueue);
|
|
|
|
Status = GetLinkStation(pFileContext,
|
|
pClearCmd->StationId,
|
|
&pDlcObject
|
|
);
|
|
|
|
//
|
|
// All commands having an invalid station id will be just removed
|
|
// from the queue. The local busy state can be reset only
|
|
// for the existing link stations
|
|
//
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// The required space is nul, when a mew packet is checked
|
|
// in the first time, the non-null value just prevents
|
|
// us to check the commited memory in the second time.
|
|
//
|
|
|
|
if (pClearCmd->RequiredBufferSpace == 0) {
|
|
|
|
//
|
|
// We must also remove the old uncommited space,
|
|
// otherwise the same buffer size could be
|
|
// committed several times, but uncommitted only once
|
|
//
|
|
|
|
if (pDlcObject->CommittedBufferSpace != 0) {
|
|
BufUncommitBuffers(pFileContext->hBufferPool,
|
|
pDlcObject->CommittedBufferSpace
|
|
);
|
|
}
|
|
|
|
pDlcObject->CommittedBufferSpace =
|
|
pClearCmd->RequiredBufferSpace = LlcGetCommittedSpace(pDlcObject->hLlcObject);
|
|
|
|
BufCommitBuffers(pFileContext->hBufferPool,
|
|
pDlcObject->CommittedBufferSpace
|
|
);
|
|
}
|
|
|
|
//
|
|
// We are be removing a local buffer busy state =>
|
|
// we must expand the buffer pools before the local busy
|
|
// is removed, but only if we are not calling this
|
|
// from a DPC level.
|
|
//
|
|
|
|
if (BufGetUncommittedSpace(pFileContext->hBufferPool) < 0) {
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
#if DBG
|
|
BufferPoolExpand(pFileContext, pFileContext->hBufferPool);
|
|
#else
|
|
BufferPoolExpand(pFileContext->hBufferPool);
|
|
#endif
|
|
|
|
ENTER_DLC(pFileContext);
|
|
}
|
|
|
|
//
|
|
// Now we have expanded the buffer pool for the new
|
|
// flow control command, check if we have now enough
|
|
// memory to receive the commited size of data.
|
|
//
|
|
|
|
if (BufGetUncommittedSpace(pFileContext->hBufferPool) >= 0
|
|
&& pDlcObject->hLlcObject != NULL) {
|
|
|
|
ReferenceLlcObject(pDlcObject);
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
Status = LlcFlowControl(pDlcObject->hLlcObject,
|
|
LLC_RESET_LOCAL_BUSY_BUFFER
|
|
);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
|
|
DereferenceLlcObject(pDlcObject);
|
|
} else {
|
|
|
|
//
|
|
// We must exit this loop when there is not enough available
|
|
// space in the buffer pool, but we must return
|
|
// the command back to the head of the list
|
|
//
|
|
|
|
LlcInsertHeadList(&pFileContext->FlowControlQueue, pClearCmd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pClearCmd);
|
|
|
|
}
|
|
|
|
DereferenceBufferPool(pFileContext);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DlcReallocate(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure changes the number of link stations allocated to a SAP
|
|
without closing or reopening the sap station.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_OBJECT pSap;
|
|
UCHAR ExtraStations;
|
|
UCHAR StationCount;
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
//
|
|
// Procedure checks the sap and returns the requested sap station.
|
|
// The error status indicates an invalid sap station id.
|
|
//
|
|
|
|
Status = GetSapStation(pFileContext,
|
|
pDlcParms->DlcReallocate.usStationId,
|
|
&pSap
|
|
);
|
|
if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// The new link station count must be more than current number
|
|
// of open link stations but less than the available number
|
|
// of link stations for the file context
|
|
//
|
|
|
|
StationCount = pDlcParms->DlcReallocate.uchStationCount;
|
|
if (StationCount != 0 && Status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Bit7 set in options => decrease the number of available
|
|
// stations by the given station count. Otherwise we increase it.
|
|
//
|
|
|
|
if (pDlcParms->DlcReallocate.uchOption & 0x80) {
|
|
ExtraStations = pSap->u.Sap.MaxStationCount - pSap->u.Sap.LinkStationCount;
|
|
if (StationCount > ExtraStations) {
|
|
StationCount = ExtraStations;
|
|
Status = DLC_STATUS_INADEQUATE_LINKS;
|
|
}
|
|
pFileContext->LinkStationCount += StationCount;
|
|
pSap->u.Sap.MaxStationCount -= StationCount;
|
|
} else {
|
|
if (pFileContext->LinkStationCount < StationCount) {
|
|
StationCount = pFileContext->LinkStationCount;
|
|
Status = DLC_STATUS_INADEQUATE_LINKS;
|
|
}
|
|
pFileContext->LinkStationCount -= StationCount;
|
|
pSap->u.Sap.MaxStationCount += StationCount;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the return parameters even if there would be an error
|
|
// (inadequate stations is a non fatal error)
|
|
//
|
|
|
|
pDlcParms->DlcReallocate.uchStationsAvailOnAdapter = pFileContext->LinkStationCount;
|
|
pDlcParms->DlcReallocate.uchStationsAvailOnSap = pSap->u.Sap.MaxStationCount - pSap->u.Sap.LinkStationCount;
|
|
pDlcParms->DlcReallocate.uchTotalStationsOnAdapter = MAX_LINK_STATIONS;
|
|
pDlcParms->DlcReallocate.uchTotalStationsOnSap = pSap->u.Sap.MaxStationCount;
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DlcReset(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure closes immediately a sap and its all link stations or
|
|
all saps and all link stations.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
STATUS_PENDING
|
|
DLC_STATUS_NO_MEMORY
|
|
--*/
|
|
|
|
{
|
|
PDLC_OBJECT pDlcObject;
|
|
PDLC_CLOSE_WAIT_INFO pClosingInfo;
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
//
|
|
// Station id 0 resets the whole DLC
|
|
//
|
|
|
|
if (pDlcParms->Async.Ccb.u.dlc.usStationId == 0) {
|
|
|
|
PDLC_CLOSE_WAIT_INFO pClosingInfo;
|
|
|
|
pClosingInfo = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
|
|
|
|
if (pClosingInfo == NULL) {
|
|
Status = DLC_STATUS_NO_MEMORY;
|
|
} else {
|
|
CloseAllStations(pFileContext,
|
|
pIrp,
|
|
DLC_COMMAND_COMPLETION,
|
|
NULL,
|
|
pDlcParms,
|
|
pClosingInfo
|
|
);
|
|
Status = STATUS_PENDING;
|
|
}
|
|
} else {
|
|
|
|
BOOLEAN allClosed;
|
|
|
|
//
|
|
// We have a specific sap station
|
|
//
|
|
|
|
Status = GetSapStation(pFileContext,
|
|
pDlcParms->Async.Ccb.u.dlc.usStationId,
|
|
&pDlcObject
|
|
);
|
|
if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Allocate the close/reset command completion info,
|
|
// the station count is the number of link stations and
|
|
// the sap station itself
|
|
//
|
|
|
|
pClosingInfo = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
|
|
|
|
if (pClosingInfo == NULL) {
|
|
return DLC_STATUS_NO_MEMORY;
|
|
}
|
|
pClosingInfo->pIrp = pIrp;
|
|
pClosingInfo->Event = DLC_COMMAND_COMPLETION;
|
|
pClosingInfo->CancelStatus = DLC_STATUS_CANCELLED_BY_USER;
|
|
pClosingInfo->CloseCounter = 1; // keep command alive over sync path
|
|
|
|
(USHORT)(pDlcObject->u.Sap.LinkStationCount + 1);
|
|
|
|
CloseAnyStation(pDlcObject, pClosingInfo, FALSE);
|
|
|
|
//
|
|
// RLF 05/09/93
|
|
//
|
|
// PC/3270 (DOS program) is hanging forever when we try to quit.
|
|
// It is doing this because we returned STATUS_PENDING to a DLC.RESET,
|
|
// even though the reset completed; the DOS program spins forever on
|
|
// the CCB.uchDlcStatus field, waiting for it to go non-0xFF, which it
|
|
// will never do.
|
|
//
|
|
// If we determine that the station has been reset (all links closed)
|
|
// then return success, else pending
|
|
//
|
|
|
|
allClosed = DecrementCloseCounters(pFileContext, pClosingInfo);
|
|
|
|
//
|
|
// RLF 07/21/92 Always return PENDING. Can't complete before return?
|
|
//
|
|
|
|
Status = allClosed ? STATUS_SUCCESS : STATUS_PENDING;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DirSetExceptionFlags(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure sets the exception flags for the current adapter context.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
pFileContext->AdapterCheckFlag = pDlcParms->DirSetExceptionFlags.ulAdapterCheckFlag;
|
|
pFileContext->NetworkStatusFlag = pDlcParms->DirSetExceptionFlags.ulNetworkStatusFlag;
|
|
pFileContext->PcErrorFlag = pDlcParms->DirSetExceptionFlags.ulPcErrorFlag;
|
|
pFileContext->SystemActionFlag = pDlcParms->DirSetExceptionFlags.ulSystemActionFlag;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
CompleteAsyncCommand(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN UINT Status,
|
|
IN PIRP pIrp,
|
|
IN PVOID pUserCcbPointer,
|
|
IN BOOLEAN InCancel
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure completes an asynchronous DLC command.
|
|
It also copies the optional output parameters to user parameter
|
|
table, if there is the second output buffer.
|
|
|
|
Arguments:
|
|
|
|
pFileContext - DLC driver client context.
|
|
Status - status of the complete command.
|
|
pIrp - the completed I/O request packet.
|
|
pUserCcbPointer - the next CCB address to which the command will be linked.
|
|
InCancel - TRUE if called on Irp cancel path
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNT_DLC_PARMS pDlcParms;
|
|
|
|
UNREFERENCED_PARAMETER(pFileContext);
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
DIAG_FUNCTION("CompleteAsyncCommand");
|
|
|
|
pDlcParms = (PNT_DLC_PARMS)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// We first map the 32-bit DLC driver status code to 8- bit API status
|
|
//
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
pDlcParms->Async.Ccb.uchDlcStatus = (UCHAR)STATUS_SUCCESS;
|
|
} else if (Status >= DLC_STATUS_ERROR_BASE && Status < DLC_STATUS_MAX_ERROR) {
|
|
|
|
//
|
|
// We can map the normal DLC error codes directly to the 8-bit
|
|
// DLC API error codes.
|
|
//
|
|
|
|
pDlcParms->Async.Ccb.uchDlcStatus = (UCHAR)(Status - DLC_STATUS_ERROR_BASE);
|
|
} else {
|
|
|
|
//
|
|
// we have an unknown NT error status => we will return it in the CCB
|
|
//
|
|
|
|
pDlcParms->Async.Ccb.uchDlcStatus = (UCHAR)(DLC_STATUS_NT_ERROR_STATUS & 0xff);
|
|
}
|
|
pDlcParms->Async.Ccb.pCcbAddress = pUserCcbPointer;
|
|
|
|
//
|
|
// We always return success status to the I/O system. The actual status is
|
|
// copied to the CCB (= the dafault output buffer)
|
|
//
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
RELEASE_DRIVER_LOCK();
|
|
|
|
DlcCompleteIoRequest(pIrp, InCancel);
|
|
|
|
ACQUIRE_DRIVER_LOCK();
|
|
|
|
ENTER_DLC(pFileContext);
|
|
|
|
DereferenceFileContext(pFileContext);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetLinkStation(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN USHORT StationId,
|
|
OUT PDLC_OBJECT *ppLinkStation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure checks and returns link station
|
|
|
|
Arguments:
|
|
|
|
pFileContext - DLC driver client context
|
|
StationId - DLC station id (ssnn, where ss = sap and nn = link station id
|
|
ppDlcObject - the returned link station
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
DLC_STATUS_INVALID_SAP_VALUE
|
|
DLC_STATUS_INVALID_STATION_ID
|
|
|
|
--*/
|
|
|
|
{
|
|
if ((StationId & 0xff) == 0 || (StationId & 0xff00) == 0) {
|
|
return DLC_STATUS_INVALID_STATION_ID;
|
|
}
|
|
return GetStation(pFileContext, StationId, ppLinkStation);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetSapStation(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN USHORT StationId,
|
|
OUT PDLC_OBJECT *ppStation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure checks and returns link station
|
|
|
|
Arguments:
|
|
|
|
pFileContext - DLC driver client context
|
|
StationId - DLC station id (ssnn, where ss = sap and nn = link station id
|
|
ppDlcObject - the returned link station
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
DLC_STATUS_INVALID_SAP_VALUE
|
|
DLC_STATUS_INVALID_STATION_ID
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT SapId = StationId >> 9;
|
|
|
|
if (SapId >= MAX_SAP_STATIONS
|
|
|| SapId == 0
|
|
|| (StationId & GROUP_SAP_BIT)
|
|
|| (*ppStation = pFileContext->SapStationTable[SapId]) == NULL
|
|
|| (*ppStation)->State != DLC_OBJECT_OPEN) {
|
|
return DLC_STATUS_INVALID_SAP_VALUE;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetStation(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN USHORT StationId,
|
|
OUT PDLC_OBJECT *ppStation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure checks the given station id and returns a pointer to
|
|
sap, direct or link station object.
|
|
|
|
Arguments:
|
|
|
|
pFileContext - DLC driver client context
|
|
StationId - DLC station id (ssnn, where ss = sap and nn = link station id
|
|
ppStation - the returned station object
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
DLC_STATUS_INVALID_STATION_ID
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT SapId = StationId >> 9;
|
|
|
|
//
|
|
// Check if the sap or direct station exists,
|
|
// but check also the link station, if we found a valid sap id.
|
|
//
|
|
|
|
if (SapId >= MAX_SAP_STATIONS
|
|
|| (StationId & GROUP_SAP_BIT)
|
|
|| (*ppStation = pFileContext->SapStationTable[SapId]) == NULL
|
|
|| (*ppStation)->State != DLC_OBJECT_OPEN) {
|
|
if (SapId == 0) {
|
|
return DLC_STATUS_DIRECT_STATIONS_NOT_AVAILABLE;
|
|
} else {
|
|
return DLC_STATUS_INVALID_STATION_ID;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The link station table will never be read, if we have found
|
|
// a valid sap or direct station. Link station must exist and
|
|
// it must be opened.
|
|
//
|
|
|
|
if (SapId != 0
|
|
&& (StationId & 0xff) != 0
|
|
&& (*ppStation = pFileContext->LinkStationTable[((StationId & 0xff) - 1)]) == NULL
|
|
|| (*ppStation)->State != DLC_OBJECT_OPEN) {
|
|
return DLC_STATUS_INVALID_STATION_ID;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DlcReadCancel(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This primitive cancels a READ command, that have the given CCB pointer.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC process specific adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
DLC_STATUS:
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PVOID pCcbAddress = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
DLC_TRACE('Q');
|
|
|
|
return AbortCommand(pFileContext,
|
|
(USHORT)DLC_IGNORE_STATION_ID,
|
|
(USHORT)DLC_STATION_MASK_SPECIFIC,
|
|
pDlcParms->DlcCancelCommand.CcbAddress,
|
|
&pCcbAddress,
|
|
DLC_STATUS_CANCELLED_BY_USER,
|
|
TRUE // Suppress completion
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DirOpenAdapter(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This primitive binds the DLC API driver to an adapter context of
|
|
the LLC module. The LLC mode may also bind to the given NDIS driver
|
|
and open it, if this is the first reference to the driver from DLC.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC process specific adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
DLC_STATUS:
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
UINT OpenErrorCode;
|
|
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
if (pDlcParms->DirOpenAdapter.NtDlcIoctlVersion != NT_DLC_IOCTL_VERSION) {
|
|
return DLC_STATUS_INVALID_VERSION;
|
|
}
|
|
|
|
//
|
|
// This makes the DirOpenAdapter safe, even if there were two adapter
|
|
// opens going on simultaneously
|
|
//
|
|
|
|
//
|
|
// RLF 04/22/94
|
|
//
|
|
// this only protects against 2 threads in the same process performing
|
|
// simultaneous opens on the same adapter
|
|
//
|
|
|
|
if (pFileContext->pBindingContext) {
|
|
return DLC_STATUS_DUPLICATE_COMMAND;
|
|
}
|
|
pFileContext->pBindingContext = (PVOID)-1;
|
|
|
|
//
|
|
// if a buffer pool handle was supplied (i.e. the app already created a
|
|
// buffer pool or is otherwise sharing one) then reference it for this
|
|
// file context
|
|
//
|
|
|
|
if (pDlcParms->DirOpenAdapter.hBufferPoolHandle) {
|
|
Status = BufferPoolReference(pDlcParms->DirOpenAdapter.hBufferPoolHandle,
|
|
&pFileContext->hBufferPool
|
|
);
|
|
if (Status == STATUS_SUCCESS) {
|
|
pFileContext->BufferPoolReferenceCount = 1;
|
|
pFileContext->hExternalBufferPool = pDlcParms->DirOpenAdapter.hBufferPoolHandle;
|
|
} else {
|
|
|
|
//
|
|
// Invalid buffer pool handle, hopefully this status
|
|
// code indicates correctly, that the buffer pool
|
|
// handle is not valid.
|
|
//
|
|
|
|
pFileContext->pBindingContext = NULL;
|
|
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
|
}
|
|
}
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
//
|
|
// XXXXXXX: BringUpDiagnostics are still missing!!!
|
|
//
|
|
|
|
//
|
|
// RLF 04/19/93
|
|
//
|
|
// The string we pass to LlcOpenAdapter is a pointer to a zero terminated
|
|
// wide character string, NOT a pointer to a UNICODE_STRING structure. The
|
|
// string MUST be in system memory space, i.e. copied across the kernel
|
|
// interface by NtDeviceIoControlFile
|
|
//
|
|
|
|
Status = LlcOpenAdapter(&pDlcParms->DirOpenAdapter.Buffer[0],
|
|
(PVOID)pFileContext,
|
|
LlcCommandCompletion,
|
|
LlcReceiveIndication,
|
|
LlcEventIndication,
|
|
NdisMedium802_5, // Always token-ring!
|
|
pDlcParms->DirOpenAdapter.LlcEthernetType,
|
|
pDlcParms->DirOpenAdapter.AdapterNumber,
|
|
&pFileContext->pBindingContext,
|
|
&OpenErrorCode,
|
|
&pFileContext->MaxFrameLength,
|
|
&pFileContext->ActualNdisMedium
|
|
);
|
|
|
|
//
|
|
// make sure LlcOpenAdapter didn't return with lowered IRQL
|
|
//
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
//
|
|
// IBM LAN Tech. Ref. defines the open error code as a 16-bit value, the
|
|
// high 8 bits of which are 0. The MAC inclusive-ORs the open error code
|
|
// into the NDIS status. Extract it
|
|
//
|
|
|
|
pDlcParms->DirOpenAdapter.Adapter.usOpenErrorCode = (USHORT)(UCHAR)OpenErrorCode;
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
ENTER_DLC(pFileContext);
|
|
|
|
//
|
|
// It does not matter, if we have null buffer pool handle!
|
|
//
|
|
|
|
#if DBG
|
|
|
|
BufferPoolDereference(pFileContext,
|
|
(PDLC_BUFFER_POOL*)&pFileContext->hBufferPool
|
|
);
|
|
|
|
#else
|
|
|
|
BufferPoolDereference((PDLC_BUFFER_POOL*)&pFileContext->hBufferPool);
|
|
|
|
#endif
|
|
|
|
//
|
|
// set the BINDING_CONTEXT pointer back to NULL - other routines check
|
|
// for this value, like CloseAdapterFileContext
|
|
//
|
|
|
|
pFileContext->pBindingContext = NULL;
|
|
|
|
//
|
|
// Probably the adapter was missing or it was installed improperly
|
|
//
|
|
|
|
Status = DLC_STATUS_ADAPTER_NOT_INSTALLED;
|
|
} else {
|
|
|
|
//
|
|
// Set the optional timer tick one/two values
|
|
// (if they have been set in registry)
|
|
//
|
|
|
|
LlcSetInformation(pFileContext->pBindingContext,
|
|
DLC_INFO_CLASS_DLC_TIMERS,
|
|
(PLLC_SET_INFO_BUFFER)&(pDlcParms->DirOpenAdapter.LlcTicks),
|
|
sizeof(LLC_TICKS)
|
|
);
|
|
|
|
LlcQueryInformation(pFileContext->pBindingContext,
|
|
DLC_INFO_CLASS_DIR_ADAPTER,
|
|
(PLLC_QUERY_INFO_BUFFER)pDlcParms->DirOpenAdapter.Adapter.auchNodeAddress,
|
|
sizeof(LLC_ADAPTER_INFO)
|
|
);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
|
|
//
|
|
// take the missing parameters from the hat
|
|
//
|
|
|
|
pDlcParms->DirOpenAdapter.Adapter.usOpenOptions = 0;
|
|
pDlcParms->DirOpenAdapter.Adapter.usMaxFrameSize = (USHORT)(pFileContext->MaxFrameLength + 6);
|
|
pDlcParms->DirOpenAdapter.Adapter.usBringUps = 0;
|
|
pDlcParms->DirOpenAdapter.Adapter.InitWarnings = 0;
|
|
|
|
pFileContext->AdapterNumber = pDlcParms->DirOpenAdapter.AdapterNumber;
|
|
pFileContext->LinkStationCount = 255;
|
|
pFileContext->pSecurityDescriptor = pDlcParms->DirOpenAdapter.pSecurityDescriptor;
|
|
|
|
//
|
|
// Read the most recent cumulative NDIS error counters
|
|
// to the file context. DLC error counters will be counted
|
|
// from 0 and they may be reset.
|
|
//
|
|
|
|
GetDlcErrorCounters(pFileContext, NULL);
|
|
pFileContext->State = DLC_FILE_CONTEXT_OPEN;
|
|
}
|
|
|
|
//
|
|
// We may directly return whatever the LLC binding primitive gives us
|
|
//
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DirCloseAdapter(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This primitive initializes the close adapter operation.
|
|
It first closes all open link and sap stations and
|
|
then optionally chains the canceled commands and
|
|
receive buffers to a READ command. If no read commands
|
|
was found, then the CCBs are linked to the CCB pointer
|
|
of this command.
|
|
|
|
The actual file close should only delete the file
|
|
object, except, if the application exits, when it still has
|
|
open dlc api handles. In that case the file close routine
|
|
will call this procedure to shut down the dlc file context.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC process specific adapter context
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
STATUS_PENDING
|
|
The adapter is being closed
|
|
|
|
DLC_STATUS_ADAPTER_CLOSED
|
|
The adapter is already closed
|
|
|
|
NOTE: This is a SYNCHRONOUS return code! And will cause the IRP
|
|
to be completed
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(pDlcParms);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
DIAG_FUNCTION("DirCloseAdapter");
|
|
|
|
DLC_TRACE('J');
|
|
|
|
if (pFileContext->State != DLC_FILE_CONTEXT_OPEN) {
|
|
return DLC_STATUS_ADAPTER_CLOSED;
|
|
}
|
|
|
|
#if LLC_DBG == 2
|
|
DbgPrint( "*** Top memory consumption (before adapter close) *** \n" );
|
|
PrintMemStatus();
|
|
#endif
|
|
|
|
//
|
|
// This disables any further commands (including DirCloseAdapter)
|
|
//
|
|
|
|
pFileContext->State = DLC_FILE_CONTEXT_CLOSE_PENDING;
|
|
|
|
//
|
|
// Remove first all functional, group or multicast addresses
|
|
// set in the adapter by the current DLC application process
|
|
//
|
|
|
|
if (pFileContext->pBindingContext) {
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
LlcResetBroadcastAddresses(pFileContext->pBindingContext);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
}
|
|
|
|
//
|
|
// We must use the static closing packet, because the adapter close
|
|
// must succeed even if we could not allocate any packets
|
|
//
|
|
|
|
CloseAllStations(pFileContext,
|
|
pIrp,
|
|
DLC_COMMAND_COMPLETION,
|
|
CompleteDirCloseAdapter,
|
|
pDlcParms,
|
|
&pFileContext->ClosingPacket
|
|
);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
VOID
|
|
CompleteDirCloseAdapter(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PDLC_CLOSE_WAIT_INFO pClosingInfo,
|
|
IN PVOID pCcbLink
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finishes DIR.CLOSE.ADAPTER command
|
|
|
|
Arguments:
|
|
|
|
pFileContext - DLC adapter open context
|
|
pClosingInfo - packet structure, that includes all data of this command
|
|
pCcbLink - the orginal user mode ccb address on the next CCB, that
|
|
will be chained to the completed command.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSUME_IRQL(DISPATCH_LEVEL);
|
|
|
|
DLC_TRACE('K');
|
|
|
|
//
|
|
// reference the file context to stop any of the dereferences below, or in
|
|
// functions called by this routine destroying it
|
|
//
|
|
|
|
ReferenceFileContext(pFileContext);
|
|
|
|
//
|
|
// Disconnect (or unbind) llc driver from us
|
|
//
|
|
|
|
if (pFileContext->pBindingContext) {
|
|
|
|
LEAVE_DLC(pFileContext);
|
|
|
|
LlcDisableAdapter(pFileContext->pBindingContext);
|
|
|
|
ENTER_DLC(pFileContext);
|
|
}
|
|
if (IoGetCurrentIrpStackLocation(pClosingInfo->pIrp)->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
|
|
CompleteAsyncCommand(pFileContext, STATUS_SUCCESS, pClosingInfo->pIrp, pCcbLink, FALSE);
|
|
} else {
|
|
|
|
//
|
|
// This is a normal FILE CLOSE !!! (IRP_MJ_CLEANUP)
|
|
//
|
|
|
|
ASSERT(IoGetCurrentIrpStackLocation(pClosingInfo->pIrp)->MajorFunction == IRP_MJ_CLEANUP);
|
|
|
|
//
|
|
// Dereference for the cleanup. This will allow cleanup to become
|
|
// unblocked.
|
|
//
|
|
|
|
DereferenceFileContext(pFileContext);
|
|
}
|
|
|
|
//
|
|
// We must delete the buffer pool now, because the dereference
|
|
// of the driver object starts the final process exit
|
|
// completion, that bug chekcs, if the number of the locked
|
|
// pages is non zero.
|
|
//
|
|
|
|
DereferenceBufferPool(pFileContext);
|
|
|
|
//
|
|
// We create two references for file context, when it is created
|
|
// the other is decremented here and the other when the synchronous
|
|
// part of command completion has been done
|
|
//
|
|
|
|
pFileContext->State = DLC_FILE_CONTEXT_CLOSED;
|
|
|
|
//
|
|
// This should be the last reference of the file context
|
|
// (if no IRPs operations are in execution or pending.
|
|
//
|
|
|
|
DereferenceFileContext(pFileContext);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DlcCompleteCommand(
|
|
IN PIRP pIrp,
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PNT_DLC_PARMS pDlcParms,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure queues the given CCB to the completion list.
|
|
This routine is used to save the synchronous commands from
|
|
DLC API DLL to event queue. This must be done whenever a
|
|
synchronous command has a non null command completion flag.
|
|
|
|
Arguments:
|
|
|
|
pIrp - current io request packet
|
|
pFileContext - DLC address object
|
|
pDlcParms - the current parameter block
|
|
InputBufferLength - the length of input parameters
|
|
OutputBufferLength -
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(pIrp);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
UNREFERENCED_PARAMETER(OutputBufferLength);
|
|
|
|
if (pDlcParms->CompleteCommand.CommandCompletionFlag == 0
|
|
|| pDlcParms->CompleteCommand.pCcbPointer == NULL) {
|
|
|
|
//
|
|
// This is more likely an internal error!
|
|
//
|
|
|
|
return DLC_STATUS_INTERNAL_ERROR;
|
|
}
|
|
return MakeDlcEvent(pFileContext,
|
|
DLC_COMMAND_COMPLETION,
|
|
pDlcParms->CompleteCommand.StationId,
|
|
NULL,
|
|
pDlcParms->CompleteCommand.pCcbPointer,
|
|
pDlcParms->CompleteCommand.CommandCompletionFlag,
|
|
FALSE
|
|
);
|
|
}
|