NT4/private/mvdm/vdmredir/vrdlc.h
2020-09-30 17:12:29 +02:00

1359 lines
44 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Copyright (c) 1991 Nokia Data Systems
Module Name:
vrdlc.h
Abstract:
This module is the only header file of Windows/Nt VDM DLC
interface module.
ALL STRUCTURES IN THIS FILE WHICH REFERENCE STRUCTURES IN DOS MEMORY
ARE BYTE PACKED
Author:
Antti Saarenheimo (o-anttis) 26-01-1992
Revision History:
--*/
//
// constants
//
#define DOS_DLC_MAX_SAPS 128
#define DOS_DLC_MAX_LINKS 255
#define DOS_DLC_MAX_EVENTS 64
#define LLC_DIR_MODIFY_OPEN_PARMS 0x01
#define LLC_DIR_RESTORE_OPEN_PARMS 0x02
#define LLC_DIR_SET_USER_APPENDAGE 0x2d
#define LLC_DOS_SPECIAL_COMMAND ((ULONG)(-1))
#define LLC_BREAK 0x20
#define DOS_DLC_STATUS_NO_INDICATION 0x81
#define LLC_SET_LOCAL_BUSY_BUFFER 0x20
//
// VRDLC_COMMAND_COMPLETION - this value is placed in the CCB_CMD_CMPL field
// of every CCB2 that we issue that is NOT for the VDM. This value is used to
// filter out command completions for commands that are generated by the DOS
// DLC Emulator. This stops us passing command completions through to the
// VDM that are not intended for it!
//
#define VRDLC_COMMAND_COMPLETION ((ULONG)(-2))
//
// buffer pool sizes
//
#define DOS_DLC_BUFFER_POOL_SIZE 0x00010000 // 64K
#define DOS_DLC_MIN_FREE_THRESHOLD 0x00002000 // 8K
//
// flags for CopyFrame
//
#define CF_CONTIGUOUS 0x00000001 // frame is contiguous
#define CF_BREAK 0x00000002 // options specified Break
#define CF_PARTIAL 0x00000004 // receiving partial frame
//
// default values for DOS parameter tables (DD_ = DOS DEFAULT). These replace
// the various parameters which can be specified as 0. They may be different
// to the corresponding defaults applicable to NT DLC, so we fill them in
// specifically
//
//
// defaults for BUFFER.GET:
//
#define DD_BUFFER_GET 1
//
// defaults for DIR.INITIALIZE:
//
#define DD_SRAM_ADDRESS_0 0xd800
#define DD_SRAM_ADDRESS_1 0xd400
//
// defaults for DIR.OPEN.ADAPTER, ADAPTER_PARMS:
//
#define DD_NUMBER_RCV_BUFFERS 8
#define DD_RCV_BUFFER_LENGTH 112
#define DD_DHB_BUFFER_LENGTH 600
#define DD_DATA_HOLD_BUFFERS 1
//
// defaults for DIR.OPEN.ADAPTER, DIRECT_PARMS:
//
#define DD_DIR_BUF_SIZE 160
#define DD_DIR_POOL_BLOCKS 256
//
// defaults for DIR.OPEN.ADAPTER, DLC_PARMS:
//
#define DD_DLC_MAX_SAP 2
#define DD_DLC_MAX_STATIONS 6
#define DD_DLC_MAX_GSAP 0
#define DD_DLC_T1_TICK_ONE 5
#define DD_DLC_T2_TICK_ONE 1
#define DD_DLC_Ti_TICK_ONE 25
#define DD_DLC_T1_TICK_TWO 25
#define DD_DLC_T2_TICK_TWO 10
#define DD_DLC_Ti_TICK_TWO 125
//
// defaults for DLC.OPEN.SAP:
//
#define DD_MAXOUT 2
#define DD_MAXIN 1
#define DD_MAX_RETRY_COUNT 8
#define DD_MAX_I_FIELD 600
#define DD_DLC_BUF_SIZE 160
#define DD_DLC_POOL_LEN 256
//
// macros
//
//
// DOS_PTR_TO_FLAT - given a DOS 16:16 pointer stored implicitly as a DWORD
//
#define DOS_PTR_TO_FLAT(a) (PVOID)GetVDMAddr(HIWORD(a), LOWORD(a))
//
// NEW_DOS_ADDRESS - generate a new DOS_ADDRESS, given a base DOS_ADDRESS and
// a new pointer which is some number of bytes plus the base DOS_ADDRESS
// converted to a flat pointer. For example, a DOS_ADDRESS of 1234:0000 becomes
// (on x86) a flat pointer of 0x12340. We generate a new pointer 0x12380 and
// want to convert this address back to a DOS_ADDRESS. So we use this macro.
// Offset-wrap and segment update is automatically handled
//
#define NEW_DOS_ADDRESS(b, p) ((b) + ((DWORD)(p) - (DWORD)DOS_PTR_TO_FLAT(b)))
//
// POOL_INDEX_FROM_SAP - get the index in aBufferPools for a given SAP/adapter
// combination. There are a maximum 127 SAPs per adapter, and 2 adapters which
// are available to DOS
//
#define POOL_INDEX_FROM_SAP(Sap, Adapter) ((Sap & 0xfe) | Adapter)
//
// POOL_INDEX_FROM_ID - given a station ID (high byte = SAP, low byte = link
// station), get the index to the SAP's buffer pool in aBufferPools
//
#define POOL_INDEX_FROM_ID(Id, Adapter) POOL_INDEX_FROM_SAP(HIBYTE(Id), Adapter)
//
// GET_POOL_INDEX - the original pool index macro
//
#define GET_POOL_INDEX(Adapter, usStationId) POOL_INDEX_FROM_ID(usStationId, Adapter)
//
// macros which initialize CCBs and call AcsLan
//
#define DlcFlowControl(Adapter, StationId, Options)\
LlcCommand(Adapter, LLC_DLC_FLOW_CONTROL, ((DWORD)Options << 16) + StationId)
#define DosDlcFlowControl(Adapter, StationId, Options)\
LlcCommand(Adapter, LLC_DOS_DLC_FLOW_CONTROL, ((DWORD)Options << 16) + StationId)
#define InitializeCcb(pCcb, AdapterNumber, Command, pParameter) \
RtlZeroMemory((pCcb), sizeof(*(pCcb)));\
RtlZeroMemory((pParameter), sizeof(*(pParameter)));\
(pCcb)->uchAdapterNumber = (UCHAR)AdapterNumber;\
(pCcb)->uchDlcCommand = (UCHAR)Command;\
(pCcb)->u.pParameterTable = (PLLC_PARMS)(pParameter)
#define InitializeCcb2(pCcb, AdapterNumber, Command) \
RtlZeroMemory((pCcb), sizeof(*(pCcb)));\
(pCcb)->uchAdapterNumber = (UCHAR)AdapterNumber;\
(pCcb)->uchDlcCommand = (UCHAR)Command;
#define ReceiveCancel(AdapterNumber, pCcb) \
LlcCommand(AdapterNumber, LLC_RECEIVE_CANCEL, (DWORD)pCcb)
//
// DLC_ERROR_STATUS - after calling AcsLan, if an error was returned by AcsLan
// then return that, else get the return code out of the CCB and return that
//
#define DLC_ERROR_STATUS(AcslanStatus, uchDlcStatus) \
(DWORD)((AcslanStatus == 0) ? (DWORD)uchDlcStatus : (DWORD)AcslanStatus)
//
// VRDLC_ALLOC - standard allocation strategy in VDM REDIR DLC functions
//
#define VRDLC_ALLOC(Bytes) LocalAlloc(LMEM_FIXED, Bytes)
//
// VRDLC_FREE - companion to VRDLC_ALLOC - standard allocation free strategy
//
#define VRDLC_FREE(Pointer) LocalFree((HLOCAL)Pointer)
//
// SAP_ID - get the SAP from a station ID word. Used as array index 0..127
// (corresponding to SAP 0..254 step 2)
//
#define SAP_ID(stationId) (HIBYTE(stationId) >> 1)
//
// LINK_ID - get the link station ID from a station ID word. Used as array index
// 0..254 (corresponding to link station 1..255)
//
#define LINK_ID(stationId) (LOBYTE(stationId) - 1)
//
// types
//
union _LLC_DOS_PARMS;
typedef union _LLC_DOS_PARMS LLC_DOS_PARMS, *PLLC_DOS_PARMS;
typedef DWORD DOS_ADDRESS;
typedef DOS_ADDRESS DPLLC_DOS_BUFFER;
//
// LLC_DOS_BUFFER - this is a union of all the DOS DLC data buffers. There are
// basically 3 kinds: Buffer 1, the first buffer in a chain which contains net
// address info, this can be in contigous or non-contiguous form, and Buffer 2
// format which is the 2nd and subsequent buffers in a chain. DLC uses the
// buffers for received data. Transmit data (passed from the app to DLC) can
// use a buffer (or chain of buffers) from the pool or can source its own
// buffer. The latter is preferred since taking buffers which DLC would use
// for receiving data can leave DLC in the local busy state (ie no receive
// buffers)
//
#include <packon.h>
typedef union _LLC_DOS_BUFFER {
//
// pNext is just a pointer so we can follow the chain
//
union _LLC_DOS_BUFFER * pNext;
//
// NextDosBuffer is the Buffer 2 structure defined in the IBM Lan Tech.
// Ref. pg 2-45
//
struct _NextDosBuffer {
union _LLC_DOS_BUFFER * pNextBuffer;// next frame segment
WORD cbFrame; // length of the whole rcvd frame
WORD cbBuffer; // length of this segment
WORD offUserData; // offset of data from descr header
WORD cbUserData; // length of the data
} Next;
//
// NotContiguous is the Not contiguous MAC/Data Buffer 1 structure defined
// in IBM Lan Tech. Ref. pg 2-42
//
struct _DosDlcNotContiguousFirstBuffer {
union _LLC_DOS_BUFFER * pNextBuffer; // next frame segment
WORD cbFrame; // length of entire frame
WORD cbBuffer; // length of this buffer
WORD offUserData; // user data in this struct
WORD cbUserData; // length of user data
WORD usStationId; // ssnn station id
UCHAR uchOptions; // option byte from RECEIVE param tbl
UCHAR uchMsgType; // the message type
WORD cBuffersLeft; // number of basic buffer units left
UCHAR uchRcvFS; // the received frame status
UCHAR uchAdapterNumber; // current adapter number
UCHAR cbLanHeader; // length of the LAN header
UCHAR cbDlcHeader; // length of the DLC header
UCHAR auchLanHeader[32];// LAN header of the received frame
UCHAR auchDlcHeader[4]; // DLC header of the received frame
} NotContiguous;
//
// Contiguous is the Contiguous MAC/Data Buffer 1 structure defined
// in IBM Lan Tech. Ref. pg 2-43
//
struct _DosDlcContiguousFirstBuffer {
union _LLC_DOS_BUFFER * pNextBuffer; // next frame segment
WORD cbFrame; // length of entire frame
WORD cbBuffer; // length of this buffer
WORD offUserData; // user data in this struct
WORD cbUserData; // length of user data
WORD usStationId; // ssnn station id
UCHAR uchOptions; // option byte from RECEIVE param tbl
UCHAR uchMsgType; // the message type
WORD cBuffersLeft; // number of basic buffer units left
UCHAR uchRcvFS; // the received frame status
UCHAR uchAdapterNumber;
} Contiguous;
} LLC_DOS_BUFFER, *PLLC_DOS_BUFFER;
#include <packoff.h>
//
// DOS_DLC_BUFFER_POOL - there is one of these per each SAP per adapter (max.
// 127 SAPs per adapter * max. 2 adapters = 256), kept in an array. This
// structure maintains basic information about the DOS buffer pool - its
// starting address (dpBuffer) in DOS 16:16 format, the size of an individual
// buffer in the pool (BufferSize) and the number of buffers in the pool
// (BufferCount). A buffer must be an integral multiple of 16 bytes, a minimum
// length of 80 bytes and not exceeding 64K-16 (0xfff0 = 65520)
//
typedef struct _DOS_DLC_BUFFER_POOL {
DOS_ADDRESS dpBuffer;
WORD BufferSize;
WORD BufferCount;
WORD MaximumBufferCount;
} DOS_DLC_BUFFER_POOL, *PDOS_DLC_BUFFER_POOL;
//
// DOS DLC CCB aka CCB1 - see definition in IBM Lan Tech. Ref. pg 2-6
//
#include <packon.h>
typedef struct _LLC_DOS_CCB {
UCHAR uchAdapterNumber; // Adapter 0 or 1
UCHAR uchDlcCommand; // DLC command
UCHAR uchDlcStatus; // DLC command completion code
UCHAR uchReserved1; // reserved for DLC DLL
struct _LLC_DOS_CCB *pNext; // queued another CCB
DWORD ulCompletionFlag; // used in command completion
union {
PLLC_DOS_PARMS pParms; // pointer to the parameter table
struct {
WORD usStationId; // Station id
WORD usParameter; // optional parameter
} dlc;
struct {
WORD usParameter0; // first optional parameter
WORD usParameter1; // second optional parameter
} dir;
UCHAR auchBuffer[4]; // group/functional address
DWORD ulParameter;
} u;
} LLC_DOS_CCB, *PLLC_DOS_CCB;
//
// additional parameter tables not defined in (sdk\inc\) DLCAPI.H (or where
// CCB1 parameter tables different from those defined in DLCAPI.H)
//
//
// LLC_DOS_DIR_INITIALIZE_PARMS - CCB1 DIR.INITIALIZE parameter table
//
typedef struct {
WORD BringUps;
WORD SharedRamAddress;
WORD Reserved;
DWORD AdapterCheckExit;
DWORD NetworkStatusExit;
DWORD PcErrorExit;
} LLC_DOS_DIR_INITIALIZE_PARMS, *PLLC_DOS_DIR_INITIALIZE_PARMS;
//
// ADAPTER_PARMS, DIRECT_PARMS, DLC_PARMS and NCB_PARMS - these are the
// parameter tables which are passed in to DIR.OPEN.ADAPTER
//
//
// ADAPTER_PARMS - parameters returned from the adapter support s/w
//
typedef struct _ADAPTER_PARMS {
WORD OpenErrorCode; // error detected opening adapter
WORD OpenOptions; // options for Token Ring only:
//
// OpenOptions Bit Meanings
//
// This has been paraphrased from the IBM Lan Tech. Ref. p3-22. I don't
// understand most of it, but I think I made it easier to read than the
// IBM technicalese. Note: ONLY MEANINGFUL TO TOKEN RING ADAPTER
//
// Bit 15: Wrap Interface
// The adapter doesn't attach to the network; instead, all
// transmitted data is reflected back as received data
//
// Bit 14: Disable Hard Error
// Stops network status change involving "Hard Error" and
// "Transmit Beacon" bits from generating interrupt
//
// Bit 13: Disable Soft Errors
// Stops network status change involving "Soft Error" bit
// generating interrupt
//
// Bit 12: Pass Adapter MAC Frames
// Unsupported MAC frames are passed to the direct station.
// If OFF, these frames are ignored
//
// Bit 11: Pass Attention MAC Frames
// Passes attention MAC frames which are not the same as the last
// received Attention MAC Frame to the direct station. If OFF,
// these frames are not passed to the direct station (ie App)
//
// Bit 10: Reserved
// Should be zero, but not checked by adapter
//
// Bit 9: Pass Parameter Table
// If the adapter is already open, returns options specified
//
// Bit 8: Contender
// If ON, this adapter will participate in monitor contention
// (claim token), should the need arise. If OFF, and it is
// another adapter decides it is necessary to claim the token,
// this adapter will not participate
//
// If this adapter decides it is necessary to determine a new
// active monitor, this adapter will initiate monitor contention
// processing IRRESPECTIVE OF THE VALUE OF THIS BIT
//
// Bit 7: Pass Beacon MAC Frames
// Pass to direct station first Beacon MAC frame and all subsequent
// Beacon MAC frames having a change in source address or beacon type
//
// Bit 6: Reserved
// Should be zero, but not checked by adapter
//
// Bit 5: Remote Program Load
// Only implemented on 16/4 adapters. Prevents adapter becoming
// a monitor during open process. If ON, will cause this adapter
// to fail the open if there are no other active adapters on the
// ring when it tries to insert itself
//
// Bit 4: Token Release
// Only implemented on 16/4 adapters and only available when
// operating at 16 Mbps. OFF: use early token release (default).
// ON: selects no early token release for adapter a 16 Mbps
//
// Bit 3: Reserved \
// Bit 2: Reserved > Should be 0, but are not checked by adapter
// Bit 1: Reserved /
// Bit 0: Reserved /
//
BYTE NodeAddress[6]; // this adapter's address
DWORD GroupAddress; // group address to set
DWORD FunctionalAddress; // functional address to set
WORD NumberReceiveBuffers; // number of receive buffers
WORD ReceiveBufferLength; // size of receive buffer
WORD DataHoldBufferLength; // size of transmit data hold buffer
BYTE NumberDataHoldBuffers; // returned: only by Token Ring
BYTE Reserved;
WORD OpenLock; // Protection code to control closing adapter
// This is NOT RETURNED when OpenOptions.9
// is set (Pass parameter table)
DWORD ProductId; // 18-byte product ID
// This is NOT RETURNED when OpenOptions.9
// is set (Pass parameter table)
//
// according to table 3-9 in IBM LAN Tech. Ref. (p3-25) the ProductId field
// should point at an 18-byte buffer formatted like so:
//
// Byte 0 0x01 indicates workstation
// Byte 1 0x10
// Byte 2-5 last 4 digits from workstation serial number in EBCDIC
// Byte 6-17 0x00
//
} ADAPTER_PARMS, *PADAPTER_PARMS;
//
// DIRECT_PARMS - input parameters defining Direct Station for adapter
//
typedef struct _DIRECT_PARMS {
//
// the direct buffer size is min. 80 bytes, and must be integral multiple
// of 16-bytes. If 0, default of 160 is used
//
WORD DirectBufferSize; // size of buffers in direct buffer pool
//
// direct pool blocks - number of 16-byte blocks in direct station buffer
// pool. If 0, default of 256 is used (= 4096 byte buffer pool)
//
WORD DirectPoolBlocks; // size of buffer in 16-byte blocks
//
// direct buffer pool - segment address in workstation memory where direct
// station buffer pool is created. Spec. doesn't say what happens if there
// is a non-zero (or any, for that matter) offset. If 0, the application
// must build the direct station buffer pool, in which case DirectBufferSize
// must indicate the size of each buffer
//
DWORD DirectBufferPool; // start address of direct buffer pool
//
// adapter check exit - vectors to this address when the adapter detects
// an internal error. If 0, the value specified in DIR.INITIALIZE is used
//
DWORD AdapterCheckExit; // I/O appendage exit: adapter check
//
// network status exit - vectors to this address when the network status
// changes (whatever that means). If 0, the value specified by
// DIR.INITIALIZE is used
//
DWORD NetworkStatusExit; // I/O appendage exit: network status change
//
// PC error exit - vectors to this address when the adapter s/w detects an
// error in the workstation (!). If 0, the value specified by DIR.INITIALIZE
// is used
//
DWORD PcErrorExit; // I/O appendage exit: error in workstation
//
// adapter work area - segment of area of w/s memory which is to be used
// by the adapter. Ignored if AdapterWorkAreaRequested is 0
//
DWORD AdapterWorkArea; // TR: adapter work are
//
// adapter work area length (requested) - the size of the workspace area,
// the segment of which is specified in AdapterWorkArea. Size is calculated
// thus: Number of SAPs x 36 + Number of stations (links) x 6 + 48
//
WORD AdapterWorkAreaRequested; // TR: work area length requested
//
// adapter work area length (actual) - this value is returned by the
// adapter. It is the amount of the work area used by the adapter (in bytes).
// If this is greater than AdapterWorkAreaRequested then an error is returned
// (0x12)
WORD AdapterWorkAreaActual; // TR: actual work area length taken
} DIRECT_PARMS, *PDIRECT_PARMS;
//
// DLC_PARMS - returned values defining DLC limits
//
typedef struct _DLC_PARMS {
//
// maximum number of concurrently opened SAPs: limited by available
// adapter memory and/or workspace memory. Maximum is 127 (126 if NetBIOS
// is specified). If 0, the default 2 is used
//
BYTE MaxSaps; // maximum number of SAPs
//
// maximum number of concurrently opened link stations: limited by
// available adapter and/or work area memory in workstation. Maximum is 255
// for Token Ring, Ethernet or PC Network. If 0, the default of 6 is used
//
BYTE MaxStations; // maximum number of link stations
//
// maximum number of group SAPs concurrently opened. If 0, no group SAPs
// can be opened. Maximum value is 126 for Token Ring, 125 for PC Network
// and Ethernet
//
BYTE MaxGroupSaps; // maximum number of group SAPs
//
// maximum number of SAPs assigned to a group. Maximum is 127 for Token
// Ring, 126 for PC Network and Ethernet
//
BYTE MaxGroupMembers; // maximum members per group SAP
//
// Timers. There are 3 timers: T1 is the Response Timer; T2 is the Inactivity
// Timer; and Ti is the Receiver Acknowledgement Timer.
//
// Timers are set to a multiple of 40ms. They count down and interrupt the
// adapter when they reach 0. Timer values can be between 1 and 10. If it
// is between 1 and 5, the short timer tick (TICK_ONE) is used and is
// referred to as group 1. If the number is between 6 and 10, the long timer
// tick (TICK_TWO) is used and is referred to as group 2. The timer value is
// the number (6 to 10) minus 5 multiplied by the long tick value.
//
//
// Tick1 - number of 40 ms ticks for short DLC timer. Defaults (if 0):
// T1 5 (200ms-400ms)
// T2 1 (40ms-80ms)
// Ti 25 (1s-2s)
//
BYTE T1Tick1; // Timer 1 short timer
BYTE T2Tick1; // Timer 2 short timer
BYTE TiTick1; // Timer i short timer
//
// Tick2 - number of 40 ms ticks for long DLC timer. Default (if 0):
// T1 25 (1s-2s)
// T2 10 (400ms-800ms)
// Ti 125 (5s-10s)
//
BYTE T1Tick2; // Timer 1 long timer
BYTE T2Tick2; // Timer 2 long timer
BYTE TiTick2; // Timer i long timer
} DLC_PARMS, *PDLC_PARMS;
//
// NCB_PARMS - we are not interested in running DOS NETBIOS over DOS DLC (are we?)
//
typedef struct _NCB_PARMS {
BYTE Reserved1[4]; // adapter work area
BYTE TimerT1;
BYTE TimerT2;
BYTE TimerTi;
BYTE MaxOut;
BYTE MaxIn;
BYTE MaxOutIncr;
BYTE MaxRetry;
BYTE Reserved2[4];
BYTE NcbAccessPri;
BYTE MaxStations;
BYTE Reserved3[19];
BYTE MaxNames;
BYTE MaxNcbs;
BYTE MaxSessions;
BYTE Reserved4[2];
BYTE Options;
WORD PoolLength;
DWORD PoolAddress;
BYTE TxTimeout;
BYTE TxCount;
} NCB_PARMS, *PNCB_PARMS;
//
// LLC_DOS_DIR_OPEN_ADAPTER_PARMS is the CCB1 DIR.OPEN.ADAPTER parameter table
//
typedef struct _LLC_DOS_DIR_OPEN_ADAPTER_PARMS {
PADAPTER_PARMS pAdapterParms;
PDIRECT_PARMS pDirectParms;
PDLC_PARMS pDlcParms;
PNCB_PARMS pNcbParms;
} LLC_DOS_DIR_OPEN_ADAPTER_PARMS, *PLLC_DOS_DIR_OPEN_ADAPTER_PARMS;
//
// LLC_DOS_RECEIVE_PARMS is the CCB1 RECEIVE parameter table
//
typedef struct _LLC_DOS_RECEIVE_PARMS {
WORD usStationId; // SAP, link station or direct id
WORD usUserLength; // length of user data in buffer header
DWORD ulReceiveExit; // the received data handler
PLLC_BUFFER pFirstBuffer; // first buffer in the pool
UCHAR uchOptions; // defines how the frame is received
} LLC_DOS_RECEIVE_PARMS, *PLLC_DOS_RECEIVE_PARMS;
//
// LLC_DOS_RECEIVE_PARMS_EX is an extended version of the LLC_DOS_RECEIVE_PARMS
// parameter table. We keep extra information - the DOS address of the original
// CCB and the original RECEIVE_DATA completion exit routine
//
typedef struct _LLC_DOS_RECEIVE_PARMS_EX {
WORD usStationId; // SAP, link station or direct id
WORD usUserLength; // length of user data in buffer header
DWORD ulReceiveExit; // the received data handler
PLLC_BUFFER pFirstBuffer; // first buffer in the pool
UCHAR uchOptions; // defines how the frame is received
UCHAR auchReserved1[3]; //
UCHAR uchRcvReadOption; // defines if rcv frames are chained
UCHAR auchReserved2[3]; // align dpOriginalCcbAddress on DWORD
DOS_ADDRESS dpOriginalCcbAddress; // dos address of orginal ccb
DOS_ADDRESS dpCompletionFlag; // orginal completion flag
} LLC_DOS_RECEIVE_PARMS_EX, *PLLC_DOS_RECEIVE_PARMS_EX;
//
// LLC_DOS_RECEIVE_MODIFY_PARMS is the parameter table for RECEIVE.MODIFY which
// we don't seem to support in NT native DLC
//
typedef struct {
WORD StationId; // SAP & link station Id
WORD UserLength; // length of user area in buffer
DWORD ReceivedDataExit; // address of routine to call with data
DWORD FirstBuffer; // pointer to first buffer from pool
DWORD Subroutine; // address of routine to call to get app buffer
} LLC_DOS_RECEIVE_MODIFY_PARMS, *PLLC_DOS_RECEIVE_MODIFY_PARMS;
//
// LLC_DOS_TRANSMIT_PARMS this structure is identical to LLC_TRANSMIT_PARMS
// except that there is no XMIT_READ_OPTION byte on the end, and the types of
// the fields are different, although the sizes are the same: eg. DOS_ADDRESS
// instead of PVOID or PLLC_XMIT_BUFFER
//
typedef struct _LLC_DOS_TRANSMIT_PARMS {
WORD usStationId; // SAP and link station ID
BYTE uchTransmitFs; // returned: Frame Status
BYTE uchRemoteSap; // remote SAP we're talking to
DOS_ADDRESS pXmitQueue1; // address of 1st buffer queue. Not pooled
DOS_ADDRESS pXmitQueue2; // address of 2nd buffer queue. Pooled
WORD cbBuffer1; // length of data in pBuffer1
WORD cbBuffer2; // length of data in pBuffer2
DOS_ADDRESS pBuffer1; // address of 1st data buffer
DOS_ADDRESS pBuffer2; // address of 2nd data buffer
} LLC_DOS_TRANSMIT_PARMS, *PLLC_DOS_TRANSMIT_PARMS;
typedef struct _LLC_MODIFY_OPEN_PARMS {
WORD usBufferSize; // block size of dlc buffers (>=80)
WORD cPoolBlocks; // number of 16 bytes blocks in buffer
DOS_ADDRESS dpPoolAddress;
DOS_ADDRESS dpAdapterCheckExit;
DOS_ADDRESS dpNetworkStatusExit;
DOS_ADDRESS dpPcErrorExit;
WORD usOpenOption;
} LLC_MODIFY_OPEN_PARMS, *PLLC_MODIFY_OPEN_PARMS;
typedef struct _DOS_DLC_DIRECT_PARMS {
WORD usBufferSize; // block size of dlc buffers (>=80)
WORD cPoolBlocks; // number of 16 bytes blocks in buffer
DOS_ADDRESS dpPoolAddress; //
DOS_ADDRESS dpAdapterCheckExit;
DOS_ADDRESS dpNetworkStatusExit;
DOS_ADDRESS dpPcErrorExit;
DWORD ulReserved1;
WORD usReserved2;
WORD usReserved3;
} DOS_DLC_DIRECT_PARMS, *PDOS_DLC_DIRECT_PARMS;
typedef struct _DOS_DLC_OPEN_SAP_PARMS {
WORD usStationId; // SAP or link station id
WORD usUserStatValue; // reserved for user
UCHAR uchT1; // response timer
UCHAR uchT2; // aknowledgment timer
UCHAR uchTi; // inactivity timer
UCHAR uchMaxOut; // max tramists without ack
UCHAR uchMaxIn; // max receives without ack
UCHAR uchMaxOutIncr; // dynamic window increment value
UCHAR uchMaxRetryCnt; // N2 value (retries)
UCHAR uchMaxMembers; // maximum members for group SAP
WORD usMaxI_Field; // maximum length of the Info field
UCHAR uchSapValue; // SAP value to be assigned
UCHAR uchOptionsPriority; // SAP options and access priority
UCHAR uchcStationCount; // maximum number of link stations in sap
UCHAR uchReserved2[2]; //
UCHAR cGroupCount; // number of group SAPs of this SAP
PUCHAR pGroupList; // offset to the group list
DWORD DlcStatusFlags; // User notify flag for DLC status changes
WORD usBufferSize; // size of individual buffer in bytes
WORD cPoolBlocks; // number of 16-byte blocks in pool
DOS_ADDRESS dpPoolAddress; // address of Buffer Pool (may be 0)
} DOS_DLC_OPEN_SAP_PARMS, *PDOS_DLC_OPEN_SAP_PARMS;
typedef struct _DOS_DIR_STATUS_PARMS {
UCHAR auchPermanentAddress[6];// permanent encoded address
UCHAR auchNodeAddress[6]; // adapter's network address
UCHAR auchGroupAddress[4]; // adapter's group address
UCHAR auchFunctAddr[4]; // adapter's functional address
UCHAR uchMaxSap; // maximum allowable SAP
UCHAR uchOpenSaps; // number of currently open saps
UCHAR uchMaxStations; // max number of stations (always 253)
UCHAR uchOpenStation; // number of open stations (only up to 253)
UCHAR uchAvailStations; // number of available stations (always 253)
UCHAR uchAdapterConfig; // adapter configuration flags
UCHAR auchMicroCodeLevel[10]; // microcode level
DOS_ADDRESS dpAdapterParmsAddr; // shared RAM address of adapter parms
DOS_ADDRESS dpAdapterMacAddr; // shared RAM address of adapter MAC buffer
DOS_ADDRESS dpTimerTick; // address of DLC timer tick counter
USHORT usLastNetworkStatus; // most recent network status issued
DOS_ADDRESS dpExtendedParms; // address of extended status table
} DOS_DIR_STATUS_PARMS, *PDOS_DIR_STATUS_PARMS;
typedef struct {
DOS_ADDRESS dpAdapterCheckExit; // adapter check appendage
DOS_ADDRESS dpNetworkStatusExit; // network status change appendage
DOS_ADDRESS dpPcErrorExit; // workstation error appendage
} LLC_DIR_SET_USER_APPENDAGE_PARMS, *PLLC_DIR_SET_USER_APPENDAGE_PARMS;
#include <packoff.h>
union _LLC_DOS_PARMS {
LLC_BUFFER_FREE_PARMS BufferFree;
LLC_BUFFER_GET_PARMS BufferGet;
LLC_DLC_CONNECT_PARMS DlcConnectStation;
LLC_DLC_MODIFY_PARMS DlcModify;
LLC_DLC_OPEN_SAP_PARMS DlcOpenSap;
LLC_DLC_OPEN_STATION_PARMS DlcOpenStation;
LLC_DLC_REALLOCATE_PARMS DlcReallocate;
LLC_DLC_SET_THRESHOLD_PARMS DlcSetThreshold;
LLC_DLC_STATISTICS_PARMS DlcStatistics;
LLC_DIR_INITIALIZE_PARMS DirInitialize;
LLC_MODIFY_OPEN_PARMS DirModifyOpenParms;
LLC_DIR_OPEN_ADAPTER_PARMS DirOpenAdapter;
LLC_DIR_OPEN_DIRECT_PARMS DirOpenDirect;
LLC_DIR_READ_LOG_PARMS DirReadLog;
LLC_DIR_SET_EFLAG_PARMS DirSetExceptionFlags;
LLC_DIR_SET_USER_APPENDAGE_PARMS DirSetUserAppendage;
LLC_DIR_STATUS_PARMS DirStatus;
DOS_DIR_STATUS_PARMS DosDirStatus;
LLC_READ_PARMS Read;
LLC_DOS_RECEIVE_PARMS_EX Receive;
LLC_DOS_RECEIVE_PARMS DosReceive;
LLC_TRANSMIT_PARMS Transmit;
LLC_TRANSMIT2_COMMAND Transmit2;
LLC_TRACE_INITIALIZE_PARMS TraceInitialize;
DOS_DLC_OPEN_SAP_PARMS DosDlcOpenSap;
};
//
// ADAPTER_TYPE - what type of network adapter we have - Token Ring, Ethernet
// or (less likely) PC network
//
typedef enum {
TokenRing,
Ethernet,
PcNetwork,
UnknownAdapter
} ADAPTER_TYPE;
//
// LOCAL_BUSY_STATE - a link station can be in 1 of 3 emulated local-busy
// (buffer) states:
//
// NOT_BUSY
// the station doesn't have any backed-up I-frames pending
//
// BUSY
// the station is in emulated local-busy(buffer) state and a
// DLC.FLOW.CONTROL(local-busy(buffer), set) has been sent to
// the DLC device driver
//
// BUSY_BUFFER
// to get out of BUSY state into CLEARING, we need at least one buffer and
// a DLC.FLOW.CONTROL from the app. Because apps can issue DLC.FLOW.CONTROL
// and BUFFER.FREE in the wrong order, we need an AND of these 2 commands
// to get going again. So we have this intermediate state where we are
// awaiting either command to restart I-Frame reception
//
// BUSY_FLOW
// Together with BUSY_BUFFER, used to create a hysteresis whereby we can't
// reach CLEARING from BUSY without getting both a DLC.FLOW.CONTROL and
// BUFFER.FREE
//
// CLEARING
// the VDM app has cleared the emulated local-busy state, but
// the DLC device driver is still in local-busy (buffer) state.
// When the last deferred I-Frame is indicated to the VDM app,
// the NT device driver local-busy(buffer) state will be reset
// and normal service will resume
//
//
// State transitions:
//
// NOT_BUSY -> BUSY
// occurs when we discover there aren't enough DOS buffers to
// receive an I-Frame. This transition is distinguished by the
// following actions:
//
// 1. DLC.FLOW.CONTROL(local-busy(buffer), set) is indicated to
// the DLC device driver
// 2. the received I-Frame is dequeued from the event queue for
// this adapter and queued on the LocalBusyInfo.Queue
// 3. a local-busy(buffer) DLC status change event is indicated to
// the DOS DLC app
//
// BUSY -> BUSY_FLOW/BUSY_BUFFER
// occurs when either a DLC.FLOW.CONTROL or BUFFER.FREE (resp) is issued
//
// BUSY_FLOW/BUSY_BUFFER -> CLEARING
// occurs when the DOS DLC app indicates we can continue receiving.
// This is done when the other (DLC.FLOW.CONTROL or BUFFER.FREE) required
// command is issued
// This transition is distinguished by the following actions:
//
// 1. DOS DLC app issues DLC.FLOW.CONTROL(local-busy(buffer), reset)
// 2. DOS DLC app *may* issue BUFFER.FREE to return receive
// buffers to the SAP pool
//
// CLEARING -> NOT_BUSY
// occurs when we indicate the last deferred receive to the DOS DLC
// app. At this point we can do the following:
//
// 1. issue DLC.FLOW.CONTROL(local-busy(buffer), reset) to the
// device driver
//
// CLEARING -> BUSY
// occurs when, during indicating deferred received I-Frames to the DOS
// DLC app, we once again run out of buffers. Again, we indicate a DLC
// status change of local-busy(buffer) to the DOS DLC app, but WE DO NOT
// indicate local-busy(buffer) to the DLC device driver (it is still in
// local-busy(buffer) state)
//
typedef enum {
NOT_BUSY = 0,
CLEARING,
BUSY,
BUSY_BUFFER,
BUSY_FLOW
} LOCAL_BUSY_STATE;
//
// LOCAL_BUSY_INFO - this structure maintains a local-busy(buffer) state
// indicator and a pointer to a queue of deferred received I-Frames per link
// station per adapter
//
typedef struct {
//
// State maintains the tri-state of the link station w.r.t. received I-Frames
//
// NOT_BUSY
// nothing queued on Queue, get next completed event from event Q
//
// BUSY
// local-busy(buffer) state has been set in DLC driver,
// awaiting buffers & flow control command from DOS DLC app
//
// CLEARING
// DOS DLC app has submitted DLC.FLOW.CONTROL(local_busy(buffer), reset)
// command, we are now trying to indicate deferred received I-Frames to
// DOS DLC app, pending enough DOS receive buffers
//
LOCAL_BUSY_STATE State;
//
// Queue - when in BUSY and CLEARING states, maintains a linked list of
// completed NT READ CCBs containing received I-Frames
//
PLLC_CCB Queue;
#if DBG
//
// track queue depth for each link station in debug version
//
DWORD Depth;
#endif
} LOCAL_BUSY_INFO;
//
// MAX_I_FRAME_DEPTH - we don't expect the queue of deferred I-Frames to grow
// beyond this small number. The deferred I-Frame queue is a buffer between
// running out of receive buffers & restarting I-Frame reception
//
#define MAX_I_FRAME_DEPTH 64 // !
//
// DOS_ADAPTER - there is one of these for each DOS adapter (i.e. 2 max.). The
// structure contains information about the virtual state of each DOS adapter.
// We record such information as the parameters used to open the adapter, the
// exit addresses and the direct station information
//
typedef struct {
//
// AdapterType - tells us what type (class?) of adapter we are using. We
// mainly use this to differentiate the types of values we return based
// on whether this is a Token Ring adapter. We get the information from
// the NT DIR.STATUS command
//
ADAPTER_TYPE AdapterType;
//
// IsOpen will be TRUE when this adapter has been successfully opened
//
BOOLEAN IsOpen;
//
// DirectStationOpen is TRUE when the direct station has been initialized
// for this adapter. This is required because the direct station is opened
// separately from the adapter in NT, but DOS expects both to be opened
// simultaneously. Hence, we only issue a DIR.OPEN.DIRECT when the DOS app
// issues a request for the direct station
//
BOOLEAN DirectStationOpen;
//
// if DirectReceive is TRUE then there is a receive outstanding on the
// direct station for this adapter
//
BOOLEAN DirectReceive;
//
// if WaitingRestore is TRUE then we must get a DIR.RESTORE.OPEN.PARMS
// before we can accept the next DIR.MODIFY.OPEN.PARMS
//
BOOLEAN WaitingRestore;
//
// BufferFree is TRUE when a BUFFER_FREE has been successfully issued for
// any station ID belonging to this adapter
//
BOOLEAN BufferFree;
//
// BufferPool is the buffer pool for this adapter's direct station
//
PVOID BufferPool;
//
// CurrentExceptionHandlers and PreviousExceptionHandlers are the addresses
// of exception 'exit' routines in DOS memory which are called asynchronously
// if one of the special exceptions occurs. These are mapped to exception
// flags in NT DLC and are presented as such in the READ CCB (ulCompletionFlag)
//
// exception handlers are always presented in the following order:
//
// Adapter Check Exit
// Network Status Exit
// PC Error Exit
//
DWORD CurrentExceptionHandlers[3];
DWORD PreviousExceptionHandlers[3];
//
// DlcStatusChangeAppendage - this appendage pointer is supplied in DLC.OPEN.SAP
// - one for each SAP. We need to keep them here because the emulator can
// generate its own DLC status change call-backs (local-busy(buffer))
//
DWORD DlcStatusChangeAppendage[DOS_DLC_MAX_SAPS];
//
// LastNetworkStatusChange is the last network status change we recorded.
// This is reported in DIR.STATUS
//
WORD LastNetworkStatusChange;
//
// UserStatusValue - we have to record the USER_STAT_VALUE from each
// successful DLC.OPEN.SAP. This is returned to the DLC status change
// appendage. We need this info for when we generate our own status change
// event (ie when we detect emulated local busy (buffer) state)
//
WORD UserStatusValue[DOS_DLC_MAX_SAPS];
//
// AdapterParms are the actual adapter parameters that this adapter was
// opened with - either specified in the DIR.OPEN.ADAPTER from the DOS
// app, or those which we use internally when we automatically open the
// adapter
//
ADAPTER_PARMS AdapterParms;
//
// DlcSpecified will be TRUE if the DLC_PARMS table was given when the
// adapter was opened (either by DIR.OPEN.ADAPTER from DOS app, or by
// DIR.OPEN.ADAPTER from automatic open)
//
BOOLEAN DlcSpecified;
//
// DlcParms - the DLC parameters specified in the open
//
DLC_PARMS DlcParms;
//
// AdapterCloseCcb - used in asynchronous adapter close when close is
// initiated by emulator
//
LLC_CCB AdapterCloseCcb;
//
// DirectCloseCcb - used in asynchronous direct station close when close is
// initiated by emulator
//
LLC_CCB DirectCloseCcb;
//
// ReadCcb - pointer to current READ CCB for this adapter
//
PLLC_CCB ReadCcb;
//
// EventQueueCritSec - must hold this while accessing EventQueue
//
CRITICAL_SECTION EventQueueCritSec;
//
// EventQueue - linked list of pending completed READ CCBs. These are linked
// by pNext field which is not normally used by READ CCB. The event queue is
// a serialized list of asynchronous events which have occurred for this
// adapter. Events are command completions, transmit completions, received
// data frames and status changes
//
PLLC_CCB EventQueueHead; // pointer to READ CCB at head of queue
PLLC_CCB EventQueueTail; // " " " " " end " "
DWORD QueueElements; // count of elements currently on EventQueue
//
// LocalBusyCritSec - must hold this while accessing DeferredReceives or
// LocalBusyInfo array
//
CRITICAL_SECTION LocalBusyCritSec;
//
// DeferredReceives - reference count of number of link stations for this
// adapter which are in local busy (buffer) state. Accessed while holding
// LocalBusyCritSec. Serves as a boolean: check for !0 to discover if there
// are deferred receives before checking all of LocalBusyInfo
//
DWORD DeferredReceives;
//
// FirstIndex and LastIndex - the start & stop points for searches through
// LocalBusyInfo. These are used in an attempt to improve searching, since
// for the vast majority of time, very few of the 255 possible slots in
// LocalBusyInfo will be used
//
// NOTE: these are array indicies, NOT link station ids (index = id - 1)
//
DWORD FirstIndex;
DWORD LastIndex;
//
// LocalBusyInfo - when a link station is in emulated local busy (buffer)
// state, we dequeue any completed received I-Frames from the event queue
// and link them onto the LocalBusyInfo list. For each adapter, there are
// 255 lists - one per link station (there are 255 possible link stations
// per adapter). The deferred receives are a list of completed NT READ CCBs
// linked by CCB.pNext field. The lists serve as a buffer between realizing
// we are out of buffers and the DLC device driver receiving the
// DLC.FLOW.CONTROL(set, buffer) command. The lists are not expected to
// grow very long
//
// This array combines the state of each link station for this adapter w.r.t.
// local-busy(buffer) and maintains the list of deferred I-Frames.
//
// The array is accessed both by the main VDM thread and the EventHandlerThread
// and so must only be accessed when holding LocalBusyCritSec
//
// Since there are 255 possible link stations per adapter and since the
// Direct Station doesn't support link stations, link station 01 uses slot
// 0, etc.
//
LOCAL_BUSY_INFO LocalBusyInfo[DOS_DLC_MAX_LINKS];
} DOS_ADAPTER, *PDOS_ADAPTER;
#define NO_LINKS_BUSY ((DWORD)0x7fffffff)
//
// DOS DLC prototypes and externals
//
extern PLLC_BUFFER aOverflowedData[];
extern DWORD OpenedAdapters;
extern DOS_ADDRESS dpVdmWindow;
//
// vrdlc5c.c
//
VOID
VrDlc5cHandler(
VOID
);
VOID
CompleteCcbProcessing(
IN LLC_STATUS Status,
IN LLC_DOS_CCB UNALIGNED * pCcb,
IN PLLC_PARMS pNtParms
);
LLC_STATUS
LlcCommand(
IN UCHAR AdapterNumber,
IN UCHAR Command,
IN DWORD Parameter
);
LLC_STATUS
BufferFree(
IN UCHAR AdapterNumber,
IN PVOID pFirstBuffer,
OUT LPWORD pusBuffersLeft
);
VOID
VrVdmWindowInit(
VOID
);
VOID
TerminateDlcEmulation(
VOID
);
//
// vrdlcbuf.c
//
VOID
InitializeBufferPools(
VOID
);
LLC_STATUS
CreateBufferPool(
IN DWORD PoolIndex,
IN DOS_ADDRESS dpBuffer,
IN WORD BufferCount,
IN WORD BufferSize
);
VOID
DeleteBufferPool(
IN DWORD PoolIndex
);
LLC_STATUS
GetBuffers(
IN DWORD PoolIndex,
IN WORD BuffersToGet,
IN DPLLC_DOS_BUFFER *pdpBuffer,
OUT LPWORD pusBuffersLeft,
IN BOOLEAN PartialList,
OUT PWORD BuffersGot OPTIONAL
);
LLC_STATUS
FreeBuffers(
IN DWORD PoolIndex,
IN DPLLC_DOS_BUFFER dpBuffer,
OUT LPWORD pusBuffersLeft
);
WORD
CalculateBufferRequirement(
IN UCHAR Adapter,
IN WORD StationId,
IN PLLC_BUFFER pFrame,
IN LLC_DOS_PARMS UNALIGNED * pDosParms,
OUT PWORD BufferSize
);
LLC_STATUS
CopyFrame(
IN PLLC_BUFFER pFrame,
IN DPLLC_DOS_BUFFER DosBuffers,
IN WORD UserLength,
IN WORD BufferSize,
IN DWORD Flags
);
BOOLEAN
AllBuffersInPool(
IN DWORD PoolIndex
);
//
// vrdlcpst.c
//
VOID
VrDlcInitialize(
VOID
);
BOOLEAN
VrDlcHwInterrupt(
VOID
);
BOOLEAN
ResetEmulatedLocalBusyState(
IN BYTE AdapterNumber,
IN WORD StationId,
IN BYTE DlcCommand
);
BOOLEAN
InitializeEventHandler(
VOID
);
PLLC_CCB
InitiateRead(
IN DWORD AdapterNumber,
OUT LLC_STATUS* ErrorStatus
);