/*++ 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 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 // // 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 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 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 );