/*++ Copyright (c) 1991 Microsoft Corporation Copyright (c) 1991 Nokia Data Systems AB Module Name: dlctyp.h Abstract: This module defines all data structures of the DLC module. Author: Antti Saarenheimo 22-Jul-1991 Environment: Kernel mode Revision History: --*/ // // forward declarations // struct _DLC_OBJECT; typedef struct _DLC_OBJECT DLC_OBJECT, *PDLC_OBJECT; struct _DLC_EVENT; typedef struct _DLC_EVENT DLC_EVENT, *PDLC_EVENT; struct _DLC_COMMAND; typedef struct _DLC_COMMAND DLC_COMMAND, *PDLC_COMMAND; struct _DLC_CLOSE_WAIT_INFO; typedef struct _DLC_CLOSE_WAIT_INFO DLC_CLOSE_WAIT_INFO, *PDLC_CLOSE_WAIT_INFO; union _DLC_PACKET; typedef union _DLC_PACKET DLC_PACKET, *PDLC_PACKET; union _DLC_BUFFER_HEADER; typedef union _DLC_BUFFER_HEADER DLC_BUFFER_HEADER; typedef DLC_BUFFER_HEADER *PDLC_BUFFER_HEADER; struct _DLC_FILE_CONTEXT; typedef struct _DLC_FILE_CONTEXT DLC_FILE_CONTEXT; typedef DLC_FILE_CONTEXT *PDLC_FILE_CONTEXT; enum _DLC_FILE_CONTEXT_STATUS { DLC_FILE_CONTEXT_OPEN, DLC_FILE_CONTEXT_CLOSE_PENDING, DLC_FILE_CONTEXT_CLOSED }; enum DlcObjectTypes { DLC_ADAPTER_OBJECT, DLC_SAP_OBJECT, DLC_LINK_OBJECT, DLC_DIRECT_OBJECT }; // // DLC structures/objects // struct _DLC_OBJECT { // // DEBUG version - we have a 16-byte identifier header for consistency // checking and to help when looking at DLC using the kernel debugger // // DBG_OBJECT_ID; // // single-linked list of link stations if this is a SAP object // PDLC_OBJECT pLinkStationList; // // pointer to owning FILE_CONTEXT // PDLC_FILE_CONTEXT pFileContext; // // pointer to RECEIVE command parameters active for this SAP/link station // PNT_DLC_PARMS pRcvParms; // // 'handle' (aka pointer to) of corresponding object in LLC // PVOID hLlcObject; PDLC_EVENT pReceiveEvent; PVOID pPrevXmitCcbAddress; PVOID pFirstChainedCcbAddress; PDLC_CLOSE_WAIT_INFO pClosingInfo; ULONG CommittedBufferSpace; USHORT ChainedTransmitCount; SHORT PendingLlcRequests; USHORT StationId; // nn00 or nnss UCHAR Type; UCHAR LinkAllCcbs; UCHAR State; BOOLEAN LlcObjectExists; USHORT LlcReferenceCount; // protects LLC objects when used // Need to have a close packet just in case we are out of resources and // can't allocate a packet to close. LLC_PACKET ClosePacket; UCHAR ClosePacketInUse; // // u - variant fields depending on object type: SAP, LINK or DIRECT station // union { struct { ULONG DlcStatusFlag; PVOID GlobalGroupSapHandle; PVOID* GroupSapHandleList; USHORT GroupSapCount; USHORT UserStatusValue; UCHAR LinkStationCount; UCHAR OptionsPriority; UCHAR MaxStationCount; } Sap; struct { struct _DLC_OBJECT* pSap; PDLC_EVENT pStatusEvent; // permanent status event USHORT MaxInfoFieldLength; } Link; struct { USHORT OpenOptions; USHORT ProtocolTypeOffset; ULONG ProtocolTypeMask; ULONG ProtocolTypeMatch; } Direct; } u; }; typedef VOID (*PFCLOSE_COMPLETE)( IN PDLC_FILE_CONTEXT pFileContext, IN PDLC_CLOSE_WAIT_INFO pClosingInfo, IN PVOID pCcbLink ); typedef BOOLEAN (*PFCOMPLETION_HANDLER)( IN PDLC_FILE_CONTEXT pFileContext, IN PDLC_OBJECT pDlcObject, IN PIRP pIrp, IN ULONG Event, IN PVOID pEventInformation, IN ULONG SecondaryInfo ); // // DLC_COMMAND and DLC_EVENT structures may be // overloaded by the code. Do not change the field // order and add the new fields only to the end. // struct _DLC_COMMAND { // // !!!!! Keep this fixed - same fields with DLC_EVENT !!!!! // LLC_PACKET LlcPacket; ULONG Event; USHORT StationId; USHORT StationIdMask; // // !!!!! Keep this fixed - same fields with DLC_EVENT !!!!! // PVOID AbortHandle; PIRP pIrp; union { PFCOMPLETION_HANDLER pfCompletionHandler; ULONG TimerTicks; } Overlay; }; struct _DLC_EVENT { LLC_PACKET LlcPacket; ULONG Event; USHORT StationId; // -1 => global event union { USHORT StationIdMask; UCHAR RcvReadOption; } Overlay; PDLC_OBJECT pOwnerObject; // if null => no owner PVOID pEventInformation; ULONG SecondaryInfo; BOOLEAN bFreeEventInfo; }; typedef struct { LLC_PACKET LlcPacket; PVOID pCcbAddress; PDLC_BUFFER_HEADER pReceiveBuffers; ULONG CommandCompletionFlag; USHORT CcbCount; USHORT StationId; } DLC_COMPLETION_EVENT_INFO, *PDLC_COMPLETION_EVENT_INFO; // // CLOSE_WAIT_INFO // // The pointer of this structure is provided to CompleteReadRequest in // the command completion of close/reset commands. The info pointer // is null for the other command completions. // struct _DLC_CLOSE_WAIT_INFO { PDLC_CLOSE_WAIT_INFO pNext; PIRP pIrp; ULONG Event; PFCLOSE_COMPLETE pfCloseComplete; PDLC_BUFFER_HEADER pRcvFrames; PVOID pCcbLink; PDLC_COMMAND pReadCommand; PDLC_COMMAND pRcvCommand; PDLC_COMPLETION_EVENT_INFO pCompletionInfo; ULONG CancelStatus; USHORT CcbCount; USHORT CloseCounter; // event sent when 0 BOOLEAN ChainCommands; BOOLEAN CancelReceive; BOOLEAN ClosingAdapter; BOOLEAN FreeCompletionInfo; }; // // This is a queued FlowControl command (the flow control commands // are completed immediately synchronously, but the local 'out of buffers' // busy state of the link is cleared when there is enough buffers // in the buffer pool to receive all expected data. // typedef struct { LIST_ENTRY List; LONG RequiredBufferSpace; USHORT StationId; } DLC_RESET_LOCAL_BUSY_CMD, *PDLC_RESET_LOCAL_BUSY_CMD; // // The transmit commands are not queued as a standard commands // but using the linked buffer headers (each frame has own xmit // header having links to buffer header list and MDL list). // The xmit nodes of the same send are queued together. // typedef struct { LLC_PACKET LlcPacket; PDLC_BUFFER_HEADER pNextSegment; PDLC_PACKET pTransmitNode; PIRP pIrp; ULONG FrameCount; PMDL pMdl; } DLC_XMIT_NODE, *PDLC_XMIT_NODE; // // DLC driver use the same packet pool for many small packets // that have approximately the same size. // union _DLC_PACKET { union _DLC_PACKET* pNext; LLC_PACKET LlcPacket; DLC_XMIT_NODE Node; DLC_EVENT Event; DLC_COMMAND DlcCommand; DLC_CLOSE_WAIT_INFO ClosingInfo; DLC_RESET_LOCAL_BUSY_CMD ClearCmd; struct { LLC_PACKET LlcPacket; PDLC_CLOSE_WAIT_INFO pClosingInfo; } ResetPacket; }; // // The buffer pool states protects the app to corrupt the buffer pool!! // All states are needed because of internal consistency checking code // and implementation of the receive. // enum _DLC_BUFFER_STATES { // // major states: // BUF_READY = 0x01, // buffer/page locked and ready for I/O BUF_USER = 0x02, // buffer owned by user BUF_LOCKED = 0x04, // buffer have been locked for I/O BUF_RCV_PENDING = 0x08, // buffer not yet chained to other frames! // // free xmit buffer when used // DEALLOCATE_AFTER_USE = 0x80 }; union _DLC_BUFFER_HEADER { // // This struct is the header of the buffers split from a page. // We save the local and global virtual addresses here. // The individual offset is always GlobalVa + Index * 256. // An entry in main page table points to this header, // if the page has been locked in the memory. // struct { PDLC_BUFFER_HEADER pNextHeader; PDLC_BUFFER_HEADER pPrevHeader; PDLC_BUFFER_HEADER pNextChild; PUCHAR pLocalVa; PUCHAR pGlobalVa; UCHAR FreeSegments; // free segments ready for alloc UCHAR SegmentsOut; // number of segments given to user UCHAR BufferState; // BUF_READY, BUF_USER, BUF_LOCKED ... UCHAR Reserved; // PMDL pMdl; } Header; // // Structure is used in the double linked free lists. // All segments having the same buffer size have been linked // to the same link list. // On another level each segment is linked to the parent (Header) // and all childs of a parent are also linked together. // struct { PDLC_BUFFER_HEADER pNext; PDLC_BUFFER_HEADER pPrev; PDLC_BUFFER_HEADER pParent; PDLC_BUFFER_HEADER pNextChild; ULONG ReferenceCount; // number of references to this buffer UCHAR Size; // size in 256 blocks UCHAR Index; // offset = Index * 256 UCHAR BufferState; // BUF_READY, BUF_USER, BUF_LOCKED ... UCHAR FreeListIndex; // PMDL pMdl; } FreeBuffer; // // The allocated frames are linked in different ways: // - the segments of the same frame are together // - the frames are linked together // These links are discarded, when the frame is given to // client (the client may free them in any order back to the buffer pool) // (The last extra pointer doesn't actually take any extra space, // because packets are round up to next 8 byte boundary) // struct { PDLC_BUFFER_HEADER pReserved; PDLC_BUFFER_HEADER pNextFrame; PDLC_BUFFER_HEADER pParent; PDLC_BUFFER_HEADER pNextChild; ULONG ReferenceCount; // number of references to this buffer UCHAR Size; // size in 256 blocks UCHAR Index; // offset = Index * 256 UCHAR BufferState; // BUF_READY, BUF_USER, BUF_LOCKED ... UCHAR FreeListIndex; PMDL pMdl; PDLC_BUFFER_HEADER pNextSegment; } FrameBuffer; PDLC_BUFFER_HEADER pNext; }; typedef struct _DLC_BUFFER_POOL { // // DEBUG version - we have a 16-byte identifier header for consistency // checking and to help when looking at DLC using the kernel debugger // // DBG_OBJECT_ID; // // control fields // struct _DLC_BUFFER_POOL* pNext; KSPIN_LOCK SpinLock; LONG ReferenceCount; // when -1 => deallocate // // buffer pool description fields (addresses, various lengths) // PVOID BaseOffset; // page-aligned base address of the pool PVOID MaxOffset; // maximum byte address in the pool + 1 ULONG MaxBufferSize; // the maximum (free) size ULONG BufferPoolSize; // size of all memory in the pool ULONG FreeSpace; // size of free memory in the pool LONG UncommittedSpace; // size of free and reserved memory LONG MissingSize; // the size missing the last request ULONG MaximumIndex; // maximum index of buffer table PVOID hHeaderPool; // packet pool for buffer headers LIST_ENTRY PageHeaders; // the allocated blocks // // pUnlockedEntryList is a singly-linked list of DLC_BUFFER_HEADERS which // describe the free pages in the pool // PDLC_BUFFER_HEADER pUnlockedEntryList; // // FreeLists is an array of doubly-linked lists - one for each size of // block that can exists in the pool. The blocks start out at a page // length (4K on x86) and are successively halved until they reach // 256 bytes which is the smallest buffer that the DLC buffer manager // can deal with // LIST_ENTRY FreeLists[DLC_BUFFER_SEGMENTS]; // // appended to the DLC_BUFFER_POOL structure is an array of pointers to // DLC_BUFFER_HEADER structures that describe the pages that comprise // the pool. There are MaximumIndex of these // PDLC_BUFFER_HEADER BufferHeaders[]; } DLC_BUFFER_POOL, *PDLC_BUFFER_POOL; // // The buffer header and frame headers have been define in the // IBM LAN Architecture reference in the end of chapter 2. // They have also been defined in dlcapi.h, but for cosmetic reason // I want to use version without those funny prefixes. // typedef struct _NEXT_DLC_SEGMENT { struct _NEXT_DLC_SEGMENT* pNext; USHORT FrameLength; USHORT DataLength; USHORT UserOffset; USHORT UserLength; } NEXT_DLC_SEGMENT, *PNEXT_DLC_SEGMENT; union _FIRST_DLC_SEGMENT; typedef union _FIRST_DLC_SEGMENT FIRST_DLC_SEGMENT, *PFIRST_DLC_SEGMENT; typedef struct { PNEXT_DLC_SEGMENT pNext; USHORT FrameLength; USHORT DataLength; USHORT UserOffset; USHORT UserLength; USHORT StationId; UCHAR Options; UCHAR MessageType; USHORT BuffersLeft; UCHAR RcvFs; UCHAR AdapterNumber; PFIRST_DLC_SEGMENT pNextFrame; } DLC_CONTIGUOUS_RECEIVE, *PDLC_CONTIGUOUS_RECEIVE; typedef struct { PNEXT_DLC_SEGMENT pNext; USHORT FrameLength; USHORT DataLength; USHORT UserOffset; USHORT UserLength; USHORT StationId; UCHAR Options; UCHAR MessageType; USHORT BuffersLeft; UCHAR RcvFs; UCHAR AdapterNumber; PFIRST_DLC_SEGMENT pNextFrame; UCHAR LanHeaderLength; UCHAR DlcHeaderLength; UCHAR LanHeader[32]; UCHAR DlcHeader[4]; } DLC_NOT_CONTIGUOUS_RECEIVE, *PDLC_NOT_CONTIGUOUS_RECEIVE; union _FIRST_DLC_SEGMENT { DLC_CONTIGUOUS_RECEIVE Cont; DLC_NOT_CONTIGUOUS_RECEIVE NotCont; }; // // Each application using DLC create its own file // context with the DlcOpenAdapter command. // struct _DLC_FILE_CONTEXT { // // all file contexts are put on single-entry list // SINGLE_LIST_ENTRY List; // linked list of file contexts #if DBG // // DEBUG version - we have a 16-byte identifier header for consistency // checking and to help when looking at DLC using the kernel debugger // // DBG_OBJECT_ID; #endif #if !defined(DLC_UNILOCK) NDIS_SPIN_LOCK SpinLock; // global lock for this file context #endif // // hBufferPool - handle of buffer pool created by BufferPoolCreate // PVOID hBufferPool; PVOID hExternalBufferPool; PVOID hPacketPool; PVOID hLinkStationPool; PVOID pBindingContext; // // Notification flags for error situations // ULONG AdapterCheckFlag; ULONG NetworkStatusFlag; ULONG PcErrorFlag; ULONG SystemActionFlag; LIST_ENTRY EventQueue; LIST_ENTRY CommandQueue; LIST_ENTRY ReceiveQueue; LIST_ENTRY FlowControlQueue; PDLC_COMMAND pTimerQueue; PVOID pSecurityDescriptor; PFILE_OBJECT FileObject; // back link to file obejct! ULONG WaitingTransmitCount; NDIS_MEDIUM ActualNdisMedium; LONG ReferenceCount; ULONG BufferPoolReferenceCount; ULONG TimerTickCounter; USHORT DlcObjectCount; // count of all DLC objects USHORT State; USHORT MaxFrameLength; UCHAR AdapterNumber; UCHAR LinkStationCount; PDLC_OBJECT SapStationTable[MAX_SAP_STATIONS]; PDLC_OBJECT LinkStationTable[MAX_LINK_STATIONS]; ULONG NdisErrorCounters[ADAPTER_ERROR_COUNTERS]; DLC_CLOSE_WAIT_INFO ClosingPacket; // to close the adapter context // Event used to make cleanup synchronous and wait for all references on // DLC_FILE_CONTEXT to be removed before completing. KEVENT CleanupEvent; #if DBG // // Debug allocation counters // MEMORY_USAGE MemoryUsage; #endif }; typedef NTSTATUS (*PFDLC_COMMAND_HANDLER)( IN PIRP pIrp, IN PDLC_FILE_CONTEXT pFileContext, IN PNT_DLC_PARMS pDlcParms, IN ULONG InputBufferLength, IN ULONG OutputBufferLength );