1871 lines
49 KiB
C
1871 lines
49 KiB
C
/*++
|
||
|
||
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
|
||
);
|
||
}
|