/*++ Copyright (c) 1991 Microsoft Corporation Module Name: llcapi.h Abstract: This module defined the kernel API of data link driver. All function prototypes and typedefs of the interface have been defined here. Author: Antti Saarenheimo (o-anttis) 17-MAY-1991 Revision History: --*/ #ifndef _LLC_API_ #define _LLC_API_ #include "llcmem.h" // // The debug switches // // // LLC_DBG: // // 0 => No debug code is generated // 1 => Enables the memory allocation accounting, state machine tracing, // procedure call tracing and internal consistency checks // 2 => Enables memory block overflow checking // // #define LLC_DBG 0 #define DBG_MP 0 // enables the MP safe versions of the accounting macros #define DLC_TRACE_ENABLED 1 // Procedure call tracing, debug only. extern NDIS_SPIN_LOCK DlcDriverLock; // // ANY_IRQL: pseudo value used in ASSUME_IRQL to mean routine is not IRQL sensitive. // Use this value with ASSUME_IRQL instead of omitting ASSUME_IRQL from a routine // (shows that we didn't forget this routine) // #define ANY_IRQL ((ULONG)-1) #if defined(LOCK_CHECK) extern LONG DlcDriverLockLevel; extern ULONG __line; extern PCHAR __file; extern LONG __last; extern HANDLE __process; extern HANDLE __thread; // // _strip - quick functionette to strip out the path garbage from __FILE__ // __inline char* _strip(char* s) { char* e = s + strlen(s) - 1; while (e != s) { if (*e == '\\') { return e + 1; } --e; } return s; } #define $$_PLACE "%s!%d" #define $$_FILE_AND_LINE _strip(__FILE__), __LINE__ // // ACQUIRE_DRIVER_LOCK - acquires the global DLC driver Spin Lock, using // NdisAcquireSpinLock(). We also check for re-entrancy and incorrect ordering // of spin lock calls // #define ACQUIRE_DRIVER_LOCK() \ { \ KIRQL currentIrql; \ HANDLE hprocess; \ HANDLE hthread; \ \ currentIrql = KeGetCurrentIrql(); \ if (currentIrql == PASSIVE_LEVEL) { \ \ PETHREAD pthread; \ \ pthread = PsGetCurrentThread(); \ hprocess = pthread->Cid.UniqueProcess; \ hthread = pthread->Cid.UniqueThread; \ } else { \ hprocess = (HANDLE)-1; \ hthread = (HANDLE)-1; \ } \ NdisAcquireSpinLock(&DlcDriverLock); \ if (++DlcDriverLockLevel != 1) { \ __last = DlcDriverLockLevel; \ DbgPrint("%d.%d:" $$_PLACE ": ACQUIRE_DRIVER_LOCK: level = %d. Last = %d.%d:" $$_PLACE "\n", \ hprocess, \ hthread, \ $$_FILE_AND_LINE, \ DlcDriverLockLevel, \ __process, \ __thread, \ __file, \ __line \ ); \ DbgBreakPoint(); \ } \ __file = _strip(__FILE__); \ __line = __LINE__; \ __process = hprocess; \ __thread = hthread; \ ASSUME_IRQL(DISPATCH_LEVEL); \ } // // RELEASE_DRIVER_LOCK - releases the global DLC driver Spin Lock, using // NdisReleaseSpinLock(). We also check for re-entrancy and incorrect ordering // of spin lock calls // #define RELEASE_DRIVER_LOCK() \ if (DlcDriverLockLevel != 1) { \ DbgPrint($$_PLACE ": RELEASE_DRIVER_LOCK: level = %d. Last = %d.%d:" $$_PLACE "\n", \ $$_FILE_AND_LINE, \ DlcDriverLockLevel, \ __process, \ __thread, \ __file, \ __line \ ); \ DbgBreakPoint(); \ } \ --DlcDriverLockLevel; \ __file = _strip(__FILE__); \ __line = __LINE__; \ NdisReleaseSpinLock(&DlcDriverLock); // // ASSUME_IRQL - used to check that a routine is being called at the IRQL we // expect. Due to the design of DLC, most functions are called at raised IRQL // (DISPATCH_LEVEL). Used mainly to assure that IRQL is at PASSIVE_LEVEL when // we do something which may incur a page fault e.g. // #define ASSUME_IRQL(level) \ if (((level) != ANY_IRQL) && (KeGetCurrentIrql() != (level))) { \ DbgPrint($$_PLACE ": ASSUME_IRQL(%d): Actual is %d\n", \ $$_FILE_AND_LINE, \ level, \ KeGetCurrentIrql() \ ); \ DbgBreakPoint(); \ } // // MY_ASSERT - since ASSERT only expands to something meaningful in the checked // build, we use this when we want an assertion check in a free build // #define MY_ASSERT(x) \ if (!(x)) { \ DbgPrint($$_PLACE ": Assertion Failed: " # x "\n", \ $$_FILE_AND_LINE \ ); \ DbgBreakPoint(); \ } // // IF_LOCK_CHECK - conditional compilation made cleaner // #define IF_LOCK_CHECK \ if (TRUE) #else #define ACQUIRE_DRIVER_LOCK() NdisAcquireSpinLock(&DlcDriverLock) #define RELEASE_DRIVER_LOCK() NdisReleaseSpinLock(&DlcDriverLock) #define ASSUME_IRQL(level) /* NOTHING */ #define MY_ASSERT(x) /* NOTHING */ #define IF_LOCK_CHECK if (FALSE) #endif // // in the Unilock DLC, we do not need the LLC spin-lock // #if defined(DLC_UNILOCK) #define ACQUIRE_LLC_LOCK(i) #define RELEASE_LLC_LOCK(i) #define ACQUIRE_SPIN_LOCK(p) #define RELEASE_SPIN_LOCK(p) #define ALLOCATE_SPIN_LOCK(p) #define DEALLOCATE_SPIN_LOCK(p) #else #define ACQUIRE_LLC_LOCK(i) KeAcquireSpinLock(&LlcSpinLock, (i)) #define RELEASE_LLC_LOCK(i) KeReleaseSpinLock(&LlcSpinLock, (i)) #define ACQUIRE_SPIN_LOCK(p) NdisAcquireSpinLock((p)) #define RELEASE_SPIN_LOCK(p) NdisReleaseSpinLock((p)) #define ALLOCATE_SPIN_LOCK(p) KeInitializeSpinLock(&(p)->SpinLock) #define DEALLOCATE_SPIN_LOCK(p) #endif // // IS_SNA_DIX_FRAME - TRUE if the frame just received & therefore described in // the ADAPTER_CONTEXT (p) has DIX framing (SNA) // #define IS_SNA_DIX_FRAME(p) \ (((PADAPTER_CONTEXT)(p))->IsSnaDixFrame) // // IS_AUTO_BINDING - TRUE if the BINDING_CONTEXT was created with // LLC_ETHERNET_TYPE_AUTO // #define IS_AUTO_BINDING(p) \ (((PBINDING_CONTEXT)(p))->EthernetType == LLC_ETHERNET_TYPE_AUTO) #define FRAME_MASK_LLC_LOCAL_DEST 0x0001 #define FRAME_MASK_NON_LLC_LOCAL_DEST 0x0002 #define FRAME_MASK_NON_LOCAL_DEST 0x0004 #define FRAME_MASK_ALL_FRAMES 0x0007 #define LLC_EXCLUSIVE_ACCESS 0x0001 #define LLC_HANDLE_XID_COMMANDS 0x0002 // // Direct station receive flags (bits 0 and 1 are inverted from dlcapi!!!) // #define DLC_RCV_SPECIFIC_DIX 0 #define DLC_RCV_MAC_FRAMES 1 #define DLC_RCV_8022_FRAMES 2 #define DLC_RCV_DIX_FRAMES 4 #define LLC_VALID_RCV_MASK 7 #define DLC_RCV_OTHER_DESTINATION 8 #define MAX_LLC_FRAME_TYPES 10 // // The DLC link states reported by DLC API // enum _DATA_LINK_STATES { // // Primary states // LLC_LINK_CLOSED = 0x80, LLC_DISCONNECTED = 0x40, LLC_DISCONNECTING = 0x20, LLC_LINK_OPENING = 0x10, LLC_RESETTING = 0x08, LLC_FRMR_SENT = 0x04, LLC_FRMR_RECEIVED = 0x02, LLC_LINK_OPENED = 0x01, // // Secondary states (when primary state is LLC_LINK_OPENED) // LLC_CHECKPOINTING = 0x80, LLC_LOCAL_BUSY_USER_SET = 0x40, LLC_LOCAL_BUSY_BUFFER_SET = 0x20, LLC_REMOTE_BUSY = 0x10, LLC_REJECTING = 0x08, LLC_CLEARING = 0x04, LLC_DYNMIC_WIN_ALG_RUNNIG = 0x02, LLC_NO_SECONDARY_STATE = 0 }; // // LAN802_ADDRESS - 8 bytes of frame address. Typically 6 bytes LAN address // plus 1 byte destination SAP, plus 1 byte source SAP // typedef union { struct { UCHAR DestSap; UCHAR SrcSap; USHORT usHigh; ULONG ulLow; } Address; struct { ULONG High; ULONG Low; } ul; struct { USHORT Raw[4]; } aus; struct { UCHAR DestSap; UCHAR SrcSap; UCHAR auchAddress[6]; } Node; UCHAR auchRawAddress[8]; } LAN802_ADDRESS, *PLAN802_ADDRESS; // // Structure is used by DlcNdisRequest function // typedef struct { NDIS_STATUS AsyncStatus; KEVENT SyncEvent; NDIS_REQUEST Ndis; } LLC_NDIS_REQUEST, *PLLC_NDIS_REQUEST; #define NDIS_INFO_BUF_SIZE 20 #define DLC_ANY_STATION (-1) // // Internal event flags used by Timer, DlcConnect // and DlcClose commands. // #define DLC_REPEATED_FLAGS 0x0700 #define LLC_TIMER_TICK_EVENT 0x0100 #define LLC_STATUS_CHANGE_ON_SAP 0x0800 // // These enum types are used also as the index of a mapping table! // enum _LLC_OBJECT_TYPES { LLC_DIRECT_OBJECT, LLC_SAP_OBJECT, LLC_GROUP_SAP_OBJECT, LLC_LINK_OBJECT, LLC_DIX_OBJECT }; // // We moved these defines here because the macro is used by data link // #define MIN_DLC_BUFFER_SEGMENT 256 ////#define MAX_DLC_BUFFER_SEGMENT 4096 //#define MAX_DLC_BUFFER_SEGMENT 8192 #define MAX_DLC_BUFFER_SEGMENT PAGE_SIZE #define BufGetPacketSize( PacketSize ) \ (((PacketSize) + 2 * MIN_DLC_BUFFER_SEGMENT - 1) & \ -MIN_DLC_BUFFER_SEGMENT) // // READ Event flags: // #define DLC_READ_FLAGS 0x007f #define LLC_SYSTEM_ACTION 0x0040 #define LLC_NETWORK_STATUS 0x0020 #define LLC_CRITICAL_EXCEPTION 0x0010 #define LLC_STATUS_CHANGE 0x0008 #define LLC_RECEIVE_DATA 0x0004 #define LLC_TRANSMIT_COMPLETION 0x0002 #define DLC_COMMAND_COMPLETION 0x0001 #define ALL_DLC_EVENTS -1 // // LLC_STATUS_CHANGE indications: // #define INDICATE_LINK_LOST 0x8000 #define INDICATE_DM_DISC_RECEIVED 0x4000 #define INDICATE_FRMR_RECEIVED 0x2000 #define INDICATE_FRMR_SENT 0x1000 #define INDICATE_RESET 0x0800 #define INDICATE_CONNECT_REQUEST 0x0400 #define INDICATE_REMOTE_BUSY 0x0200 #define INDICATE_REMOTE_READY 0x0100 #define INDICATE_TI_TIMER_EXPIRED 0x0080 #define INDICATE_DLC_COUNTER_OVERFLOW 0x0040 #define INDICATE_ACCESS_PRTY_LOWERED 0x0020 #define INDICATE_LOCAL_STATION_BUSY 0x0001 // // LLC Command completion indications. // enum _LLC_COMPLETION_CODES { LLC_RECEIVE_COMPLETION, LLC_SEND_COMPLETION, LLC_REQUEST_COMPLETION, LLC_CLOSE_COMPLETION, LLC_RESET_COMPLETION, LLC_CONNECT_COMPLETION, LLC_DISCONNECT_COMPLETION }; typedef union { LLC_ADAPTER_INFO Adapter; DLC_LINK_PARAMETERS LinkParms; LLC_TICKS Timer; DLC_LINK_LOG LinkLog; DLC_SAP_LOG SapLog; UCHAR PermanentAddress[6]; UCHAR auchBuffer[1]; } LLC_QUERY_INFO_BUFFER, *PLLC_QUERY_INFO_BUFFER; typedef union { DLC_LINK_PARAMETERS LinkParms; LLC_TICKS Timers; UCHAR auchFunctionalAddress[4]; UCHAR auchGroupAddress[4]; UCHAR auchBuffer[1]; } LLC_SET_INFO_BUFFER, *PLLC_SET_INFO_BUFFER; // // LLC_FRMR_INFORMATION - 5 bytes of FRaMe Reject code // typedef struct { UCHAR Command; // format: mmmpmm11, m=modifiers, p=poll/final. UCHAR Ctrl; // control field of rejected frame. UCHAR Vs; // our next send when error was detected. UCHAR Vr; // our next receive when error was detected. UCHAR Reason; // reason for sending FRMR: 000VZYXW. } LLC_FRMR_INFORMATION, *PLLC_FRMR_INFORMATION; // // DLC_STATUS_TABLE - format of status information returned in a READ command // typedef struct { USHORT StatusCode; LLC_FRMR_INFORMATION FrmrData; UCHAR uchAccessPriority; UCHAR auchRemoteNode[6]; UCHAR uchRemoteSap; UCHAR uchLocalSap; PVOID hLlcLinkStation; } DLC_STATUS_TABLE, *PDLC_STATUS_TABLE; typedef struct { ULONG IsCompleted; ULONG Status; } ASYNC_STATUS, *PASYNC_STATUS; union _LLC_OBJECT; typedef union _LLC_OBJECT LLC_OBJECT, *PLLC_OBJECT; struct _BINDING_CONTEXT; typedef struct _BINDING_CONTEXT BINDING_CONTEXT, *PBINDING_CONTEXT; // // LLC packet headers // // // LLC_XID_INFORMATION - 3 information bytes in a standard LLC XID packet // typedef struct { UCHAR FormatId; // format of this XID frame. UCHAR Info1; // first information byte. UCHAR Info2; // second information byte. } LLC_XID_INFORMATION, *PLLC_XID_INFORMATION; // // LLC_TEST_INFORMATION - information field for TEST frame // typedef struct { UCHAR Padding[4]; PMDL pMdl; // we keep test MDL in the same slot as U-MDL } LLC_TEST_INFORMATION, *PLLC_TEST_INFORMATION; typedef union { LLC_XID_INFORMATION Xid; // XID information. LLC_FRMR_INFORMATION Frmr; // FRMR information. LLC_TEST_INFORMATION Test; // Test MDL pointer UCHAR Padding[8]; // } LLC_RESPONSE_INFO, *PLLC_RESPONSE_INFO; // // LLC_U_HEADER - Unnumbered format frame LLC header // typedef struct { UCHAR Dsap; // Destination Service Access Point. UCHAR Ssap; // Source Service Access Point. UCHAR Command; // command code. } LLC_U_HEADER, *PLLC_U_HEADER; // // LLC_S_HEADER - Supervisory format frame LLC header // typedef struct { UCHAR Dsap; // Destination Service Access Point. UCHAR Ssap; // Source Service Access Point. UCHAR Command; // RR, RNR, REJ command code. UCHAR Nr; // receive seq #, bottom bit is poll/final. } LLC_S_HEADER, *PLLC_S_HEADER; // // LLC_I_HEADER - Information frame LLC header // typedef struct { UCHAR Dsap; // Destination Service Access Point. UCHAR Ssap; // Source Service Access Point. UCHAR Ns; // send sequence number, bottom bit 0. UCHAR Nr; // rcv sequence number, bottom bit p/f. } LLC_I_HEADER, *PLLC_I_HEADER; typedef struct { LLC_U_HEADER U; // normal U- frame UCHAR Type; // its lan header conversion type } LLC_U_PACKET_HEADER, *PLLC_U_PACKET_HEADER; typedef union { LLC_S_HEADER S; LLC_I_HEADER I; LLC_U_HEADER U; ULONG ulRawLLc; UCHAR auchRawBytes[4]; USHORT EthernetType; } LLC_HEADER, *PLLC_HEADER; typedef struct _LLC_PACKET { struct _LLC_PACKET* pNext; struct _LLC_PACKET* pPrev; UCHAR CompletionType; UCHAR cbLlcHeader; USHORT InformationLength; PBINDING_CONTEXT pBinding; union { struct { PUCHAR pLanHeader; LLC_HEADER LlcHeader; PLLC_OBJECT pLlcObject; PMDL pMdl; } Xmit; struct { PUCHAR pLanHeader; UCHAR TranslationType; UCHAR Dsap; UCHAR Ssap; UCHAR Command; PLLC_OBJECT pLlcObject; PMDL pMdl; } XmitU; struct { PUCHAR pLanHeader; UCHAR TranslationType; UCHAR EthernetTypeHighByte; UCHAR EthernetTypeLowByte; UCHAR Padding; PLLC_OBJECT pLlcObject; PMDL pMdl; } XmitDix; struct { PUCHAR pLanHeader; UCHAR TranslationType; UCHAR Dsap; UCHAR Ssap; UCHAR Command; LLC_RESPONSE_INFO Info; } Response; // // Link station data packet may be acknowledged by the other // side, before it is completed by NDIS. Ndis completion // routine expects to find pLlcObject link => we must not change // that field, when the xmit packet is translated to // a completion packet. Otherwise is corrupt pFileContext pointer, // when NdisSendCount is incremented. // struct { ULONG Status; ULONG CompletedCommand; PLLC_OBJECT pLlcObject; PVOID hClientHandle; } Completion; } Data; } LLC_PACKET, *PLLC_PACKET; // // DLC API return codes // // The base value of the error codes is not compatible with the other // nt error codes, but it doesn't matter because these are internal // for DLC driver (and its data link layer). // 16 bit- error codes are used, because in MIPS they need less // instructions (MIPS cannot load directly over 16 bits constants) // and this code can also be emuulated on OS/2. // typedef enum _DLC_STATUS { DLC_STATUS_SUCCESS = 0, DLC_STATUS_ERROR_BASE = 0x6000, DLC_STATUS_INVALID_COMMAND = 0x01 + DLC_STATUS_ERROR_BASE, DLC_STATUS_DUPLICATE_COMMAND = 0x02 + DLC_STATUS_ERROR_BASE, DLC_STATUS_ADAPTER_OPEN = 0x03 + DLC_STATUS_ERROR_BASE, DLC_STATUS_ADAPTER_CLOSED = 0x04 + DLC_STATUS_ERROR_BASE, DLC_STATUS_PARAMETER_MISSING = 0x05 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_OPTION = 0x06 + DLC_STATUS_ERROR_BASE, DLC_STATUS_COMMAND_CANCELLED_FAILURE = 0x07 + DLC_STATUS_ERROR_BASE, DLC_STATUS_CANCELLED_BY_USER = 0x0A + DLC_STATUS_ERROR_BASE, DLC_STATUS_SUCCESS_NOT_OPEN = 0x0C + DLC_STATUS_ERROR_BASE, DLC_STATUS_TIMER_ERROR = 0x11 + DLC_STATUS_ERROR_BASE, DLC_STATUS_NO_MEMORY = 0x12 + DLC_STATUS_ERROR_BASE, DLC_STATUS_LOST_LOG_DATA = 0x15 + DLC_STATUS_ERROR_BASE, DLC_STATUS_BUFFER_SIZE_EXCEEDED = 0x16 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_BUFFER_LENGTH = 0x18 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INADEQUATE_BUFFERS = 0x19 + DLC_STATUS_ERROR_BASE, DLC_STATUS_USER_LENGTH_TOO_LARGE = 0x1A + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_CCB_POINTER = 0x1B + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_POINTER = 0x1C + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_ADAPTER = 0x1D + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_FUNCTIONAL_ADDRESS = 0x1E + DLC_STATUS_ERROR_BASE, DLC_STATUS_LOST_DATA_NO_BUFFERS = 0x20 + DLC_STATUS_ERROR_BASE, DLC_STATUS_TRANSMIT_ERROR_FS = 0x22 + DLC_STATUS_ERROR_BASE, DLC_STATUS_TRANSMIT_ERROR = 0x23 + DLC_STATUS_ERROR_BASE, DLC_STATUS_UNAUTHORIZED_MAC = 0x24 + DLC_STATUS_ERROR_BASE, DLC_STATUS_LINK_NOT_TRANSMITTING = 0x27 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_FRAME_LENGTH = 0x28 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_NODE_ADDRESS = 0x32 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_RECEIVE_BUFFER_LENGTH = 0x33 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_TRANSMIT_BUFFER_LENGTH = 0x34 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_STATION_ID = 0x40 + DLC_STATUS_ERROR_BASE, DLC_STATUS_LINK_PROTOCOL_ERROR = 0x41 + DLC_STATUS_ERROR_BASE, DLC_STATUS_PARMETERS_EXCEEDED_MAX = 0x42 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_SAP_VALUE = 0x43 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_ROUTING_INFO = 0x44 + DLC_STATUS_ERROR_BASE, DLC_STATUS_LINK_STATIONS_OPEN = 0x47 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INCOMPATIBLE_COMMAND_IN_PROGRESS = 0x4A + DLC_STATUS_ERROR_BASE, DLC_STATUS_CONNECT_FAILED = 0x4D + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_REMOTE_ADDRESS = 0x4F + DLC_STATUS_ERROR_BASE, DLC_STATUS_CCB_POINTER_FIELD = 0x50 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INADEQUATE_LINKS = 0x57 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_PARAMETER_1 = 0x58 + DLC_STATUS_ERROR_BASE, DLC_STATUS_DIRECT_STATIONS_NOT_AVAILABLE = 0x5C + DLC_STATUS_ERROR_BASE, DLC_STATUS_DEVICE_DRIVER_NOT_INSTALLED = 0x5d + DLC_STATUS_ERROR_BASE, DLC_STATUS_ADAPTER_NOT_INSTALLED = 0x5e + DLC_STATUS_ERROR_BASE, DLC_STATUS_CHAINED_DIFFERENT_ADAPTERS = 0x5f + DLC_STATUS_ERROR_BASE, DLC_STATUS_INIT_COMMAND_STARTED = 0x60 + DLC_STATUS_ERROR_BASE, DLC_STATUS_CANCELLED_BY_SYSTEM_ACTION = 0x62 + DLC_STATUS_ERROR_BASE, DLC_STATUS_MEMORY_LOCK_FAILED = 0x69 + DLC_STATUS_ERROR_BASE, // // New Nt DLC specific error codes begin from 0x80 // These error codes are for new Windows/Nt DLC apps. // This far we have tried too much use the OS/2 error codes, // that results often uninformative return codes. // DLC_STATUS_INVALID_BUFFER_ADDRESS = 0x80 + DLC_STATUS_ERROR_BASE, DLC_STATUS_BUFFER_ALREADY_RELEASED = 0x81 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_VERSION = 0xA1 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INVALID_BUFFER_HANDLE = 0xA2 + DLC_STATUS_ERROR_BASE, DLC_STATUS_NT_ERROR_STATUS = 0xA3 + DLC_STATUS_ERROR_BASE, // // These error codes are just internal for LLC- kernel level interface // and they are not returned to application level. // DLC_STATUS_UNKNOWN_MEDIUM = 0xC0 + DLC_STATUS_ERROR_BASE, DLC_STATUS_DISCARD_INFO_FIELD = 0xC1 + DLC_STATUS_ERROR_BASE, DLC_STATUS_NO_ACTION = 0xC2 + DLC_STATUS_ERROR_BASE, DLC_STATUS_ACCESS_DENIED = 0xC3 + DLC_STATUS_ERROR_BASE, DLC_STATUS_IGNORE_FRAME = 0xC4 + DLC_STATUS_ERROR_BASE, DLC_STATUS_WAIT_TIMEOUT = 0xC5 + DLC_STATUS_ERROR_BASE, DLC_STATUS_NO_RECEIVE_COMMAND = 0xC6 + DLC_STATUS_ERROR_BASE, DLC_STATUS_FILE_CONTEXT_DELETED = 0xC7 + DLC_STATUS_ERROR_BASE, DLC_STATUS_EXPAND_BUFFER_POOL = 0xC8 + DLC_STATUS_ERROR_BASE, DLC_STATUS_INTERNAL_ERROR = 0xC9 + DLC_STATUS_ERROR_BASE, DLC_STATUS_ASYNC_DATA_TRANSFER_FAILED = 0xCA + DLC_STATUS_ERROR_BASE, DLC_STATUS_OUT_OF_RCV_BUFFERS = 0xCB + DLC_STATUS_ERROR_BASE, DLC_STATUS_PENDING = 0xFF + DLC_STATUS_ERROR_BASE, DLC_STATUS_MAX_ERROR = 0xFF + DLC_STATUS_ERROR_BASE } DLC_STATUS; // // Data link indication handler prototypes. // The protocols registering to data link driver // must provide these entry points. // typedef DLC_STATUS (*PFLLC_RECEIVE_INDICATION)( IN PVOID hClientContext, IN PVOID hClientHandle, IN NDIS_HANDLE MacReceiveContext, IN USHORT FrameType, IN PVOID pLookBuf, IN UINT cbLookBuf ); typedef VOID (*PFLLC_COMMAND_COMPLETE)( IN PVOID hClientContext, IN PVOID hClientHandle, IN PVOID hPacket ); typedef VOID (*PFLLC_EVENT_INDICATION)( IN PVOID hClientContext, IN PVOID hClientHandle, IN UINT uiEvent, IN PVOID pDlcStatus, IN ULONG SecondaryInformation ); UINT LlcBuildAddressFromLanHeader( IN NDIS_MEDIUM NdisMedium, IN PUCHAR pRcvFrameHeader, IN OUT PUCHAR pLanHeader ); DLC_STATUS LlcInitialize( VOID ); UINT LlcBuildAddress( IN NDIS_MEDIUM NdisMedium, IN PUCHAR DestinationAddress, IN PVOID pSrcRouting, IN OUT PUCHAR pLanHeader ); USHORT LlcGetMaxInfoField( IN NDIS_MEDIUM NdisMedium, IN PVOID hBinding, IN PUCHAR pLanHeader ); DLC_STATUS LlcQueryInformation( IN PVOID hObject, IN UINT InformationType, IN PLLC_QUERY_INFO_BUFFER pQuery, IN UINT QueryBufferSize ); DLC_STATUS LlcSetInformation( IN PVOID hObject, IN UINT InformationType, IN PLLC_SET_INFO_BUFFER pSetInfo, IN UINT ParameterBufferSize ); DLC_STATUS LlcNdisRequest( IN PVOID hBindingContext, IN PLLC_NDIS_REQUEST pDlcParms ); DLC_STATUS LlcOpenAdapter( IN PWSTR pAdapterName, IN PVOID hClientContext, IN PFLLC_COMMAND_COMPLETE pfCommandComplete, IN PFLLC_RECEIVE_INDICATION pfReceiveIndication, IN PFLLC_EVENT_INDICATION pfEventIndication, IN NDIS_MEDIUM NdisMedium, IN LLC_ETHERNET_TYPE EthernetType, IN UCHAR AdapterNumber, OUT PVOID *phBindingContext, OUT PUINT puiOpenStatus, OUT PUSHORT puiMaxFrameLength, OUT PNDIS_MEDIUM pActualNdisMedium ); #define LlcOpenSap(Context, Handle, Sap, Options, phSap) \ LlcOpenStation(Context, Handle, (USHORT)(Sap), LLC_SAP_OBJECT, (USHORT)(Options), phSap) #define LlcOpenDirectStation(Context, Handle, Sap, phSap) \ LlcOpenStation(Context, Handle, (USHORT)(Sap), LLC_DIRECT_OBJECT, 0, phSap) #define LlcOpenDixStation(Context, Handle, Sap, phSap) \ LlcOpenStation(Context, Handle, (USHORT)(Sap), LLC_DIX_OBJECT, 0, phSap) VOID RemoveFromLinkList( OUT PVOID* ppBase, IN PVOID pElement ); VOID LlcSleep( IN LONG lMicroSeconds ); VOID LlcTerminate( VOID ); VOID LlcDereferenceObject( IN PVOID pStation ); VOID LlcReferenceObject( IN PVOID pStation ); DLC_STATUS LlcTraceInitialize( IN PVOID UserTraceBuffer, IN ULONG UserTraceBufferSize, IN ULONG TraceFlags ); VOID LlcTraceClose( VOID ); VOID LlcTraceWrite( IN UINT Event, IN UCHAR AdapterNumber, IN UINT DataBufferSize, IN PVOID DataBuffer ); VOID LlcTraceDump( IN UINT LastEvents, IN UINT AdapterNumber, IN PUCHAR pRemoteNode ); VOID LlcTraceDumpAndReset( IN UINT LastEvents, IN UINT AdapterNumber, IN PUCHAR pRemoteNode ); #if DBG typedef struct { USHORT Input; USHORT Time; PVOID pLink; } LLC_SM_TRACE; #define LLC_INPUT_TABLE_SIZE 500 extern ULONG AllocatedNonPagedPool; extern ULONG LockedPageCount; extern ULONG AllocatedMdlCount; extern ULONG AllocatedPackets; extern NDIS_SPIN_LOCK MemCheckLock; extern ULONG cExAllocatePoolFailed; extern ULONG FailedMemoryLockings; VOID PrintMemStatus(VOID); extern ULONG cFramesReceived; extern ULONG cFramesIndicated; extern ULONG cFramesReleased; extern ULONG cLockedXmitBuffers; extern ULONG cUnlockedXmitBuffers; extern LLC_SM_TRACE aLast[]; extern UINT InputIndex; #endif // // The inline memcpy and memset functions are faster, // in x386 than RtlMoveMemory // #if defined(i386) #define LlcMemCpy(Dest, Src, Len) memcpy(Dest, Src, Len) #define LlcZeroMem(Ptr, Len) memset(Ptr, 0, Len) #else #define LlcMemCpy(Dest, Src, Len) RtlMoveMemory(Dest, Src, Len) #define LlcZeroMem(Ptr, Len) RtlZeroMemory(Ptr, Len) #endif // // // PVOID // PopEntryList( // IN PQUEUE_PACKET ListHead, // ); // #define PopFromList(ListHead) \ (PVOID)(ListHead); \ (ListHead) = (PVOID)(ListHead)->pNext; // // VOID // PushToList( // IN PQUEUE_PACKET ListHead, // IN PQUEUE_PACKET Entry // ); // #define PushToList(ListHead,Entry) { \ (Entry)->pNext = (PVOID)(ListHead); \ (ListHead) = (Entry); \ } // // About 30% of all bugs are related with the invalid operations with // packets. A packet may be inserted to another list before it // has been removed from the previous one, etc. // The debug version of the list macroes reset the next pointer // every time it is removed from the list and check it when it is // inserted to a new list or released to a packet pool. The packet // alloc will reset the next pointer automatically. // Problem: the packets are used for many other purposes as well => // we must do quite a lot conditional code. // #if LLC_DBG #if LLC_DBG_MP #define DBG_INTERLOCKED_INCREMENT(Count) \ InterlockedIncrement( \ (PLONG)&(Count) \ ) #define DBG_INTERLOCKED_DECREMENT(Count) \ InterlockedDecrement( \ (PLONG)&(Count) \ ) #define DBG_INTERLOCKED_ADD(Added, Value) \ ExInterlockedAddUlong( \ (PULONG)&(Added), \ (ULONG)(Value), \ &MemCheckLock.SpinLock \ ) #else #define DBG_INTERLOCKED_INCREMENT(Count) (Count)++ #define DBG_INTERLOCKED_DECREMENT(Count) (Count)-- #define DBG_INTERLOCKED_ADD(Added, Value) (Added) += (Value) #endif // LLC_DBG_MP #else #define DBG_INTERLOCKED_INCREMENT(Count) #define DBG_INTERLOCKED_DECREMENT(Count) #define DBG_INTERLOCKED_ADD(Added, Value) #endif // LLC_DBG #if LLC_DBG VOID LlcBreakListCorrupt( VOID ); #define LlcRemoveHeadList(ListHead) \ (PVOID)(ListHead)->Flink; \ { \ PLIST_ENTRY FirstEntry; \ FirstEntry = (ListHead)->Flink; \ FirstEntry->Flink->Blink = (ListHead); \ (ListHead)->Flink = FirstEntry->Flink; \ FirstEntry->Flink = NULL; \ } #define LlcRemoveTailList(ListHead) \ (ListHead)->Blink; \ { \ PLIST_ENTRY FirstEntry; \ FirstEntry = (ListHead)->Blink; \ FirstEntry->Blink->Flink = (ListHead); \ (ListHead)->Blink = FirstEntry->Blink; \ FirstEntry->Flink = NULL; \ } #define LlcRemoveEntryList(Entry) \ { \ RemoveEntryList((PLIST_ENTRY)Entry); \ ((PLIST_ENTRY)(Entry))->Flink = NULL; \ } #define LlcInsertTailList(ListHead,Entry) \ if (((PLIST_ENTRY)(Entry))->Flink != NULL){ \ LlcBreakListCorrupt(); \ } \ InsertTailList(ListHead, (PLIST_ENTRY)Entry) #define LlcInsertHeadList(ListHead,Entry) \ if (((PLIST_ENTRY)(Entry))->Flink != NULL) { \ LlcBreakListCorrupt(); \ } \ InsertHeadList(ListHead,(PLIST_ENTRY)Entry) /* #define DeallocatePacket( PoolHandle, pBlock ) { \ if (((PLIST_ENTRY)pBlock)->Flink != NULL) { \ LlcBreakListCorrupt(); \ } \ DBG_INTERLOCKED_DECREMENT( AllocatedPackets ); \ ExFreeToZone( \ &(((PEXTENDED_ZONE_HEADER)PoolHandle)->Zone), \ pBlock); \ } */ #else // // PVOID // LlcRemoveHeadList( // IN PLIST_ENTRY ListHead // ); // #define LlcRemoveHeadList(ListHead) (PVOID)RemoveHeadList(ListHead) // // PLIST_ENTRY // LlcRemoveTailList( // IN PLIST_ENTRY ListHead // ); // #define LlcRemoveTailList(ListHead) \ (ListHead)->Blink; { \ PLIST_ENTRY FirstEntry; \ FirstEntry = (ListHead)->Blink; \ FirstEntry->Blink->Flink = (ListHead); \ (ListHead)->Blink = FirstEntry->Blink; \ } // // VOID // LlcRemoveEntryList( // IN PVOID Entry // ); // #define LlcRemoveEntryList(Entry) RemoveEntryList((PLIST_ENTRY)Entry) // // VOID // LlcInsertTailList( // IN PLIST_ENTRY ListHead, // IN PVOID Entry // ); // #define LlcInsertTailList(ListHead,Entry) \ InsertTailList(ListHead, (PLIST_ENTRY)Entry) // // VOID // LlcInsertHeadList( // IN PLIST_ENTRY ListHead, // IN PVOID Entry // ); // #define LlcInsertHeadList(ListHead,Entry) \ InsertHeadList(ListHead,(PLIST_ENTRY)Entry) // // VOID // DeallocatePacket( // PEXTENDED_ZONE_HEADER PoolHandle, // PVOID pBlock // ); // /* #define DeallocatePacket( PoolHandle, pBlock ) { \ ExFreeToZone( &(((PEXTENDED_ZONE_HEADER)PoolHandle)->Zone), \ pBlock); \ } */ #endif // DBG #if LLC_DBG == 2 VOID LlcMemCheck(VOID); #define MEM_CHECK() LlcMemCheck() #else #define MEM_CHECK() #endif VOID LlcInvalidObjectType(VOID); /*++ Trace codes Big letters are reserved for actions, small letters are used to identify objects and packet types. The trace macroes simply writes to DLC trace tree (remember: we have another trace for the state machine!!!) 'a' = dix stations 'b' = direct station 'c' = link station 'd' = sap station 'e' = Connect command 'f' = Close command 'g' = Disconnect command 'h' = Receive command 'i' = transmit command 'j' = Type1 packet 'k' = type 2 packet 'l' = data link packet 'A' = CompleteSendAndLock 'B' = LlcCommandCompletion 'C' = LlcCloseStation 'D' = LlcReceiveIndication 'E' = LlcEventIndication 'F' = DlcDeviceIoControl 'G' = DlcDeviceIoControl sync exit 'H' = DlcDeviceIoControl async exit 'I' = LlcSendI 'J' = DirCloseAdapter 'K' = CompleteDirCloseAdapter 'L' = LlcDereferenceObject 'M' = LlcReferenceObject 'N' = CompleteCloseStation (final) 'O' = DereferenceLlcObject (in dlc) 'P' = CompleteLlcObjectClose (final) 'Q' = DlcReadCancel 'R' = 'S' = 'T' = DlcTransmit 'U' = LlcSendU 'V' = 'W' = 'X' = 'Y' = 'Z' = --*/ #if DBG & DLC_TRACE_ENABLED #define LLC_TRACE_TABLE_SIZE 0x400 // this must be exponent of 2! extern UINT LlcTraceIndex; extern UCHAR LlcTraceTable[]; #define DLC_TRACE(a) {\ LlcTraceTable[LlcTraceIndex] = (a);\ LlcTraceIndex = (LlcTraceIndex + 1) & (LLC_TRACE_TABLE_SIZE - 1);\ } #else #define DLC_TRACE(a) #endif // LLC_DBG // // the following functions can be macros if DLC and LLC live in the same driver // and each knows about the other's structures // #if DLC_AND_LLC // // UINT // LlcGetReceivedLanHeaderLength( // IN PVOID pBinding // ); // #if 0 // // this gives the wrong length for DIX lan header // #define LlcGetReceivedLanHeaderLength(pBinding) \ ((((PBINDING_CONTEXT)(pBinding))->pAdapterContext->NdisMedium == NdisMedium802_3) \ ? (((PBINDING_CONTEXT)(pBinding))->pAdapterContext->FrameType == LLC_DIRECT_ETHERNET_TYPE) \ ? 12 \ : 14 \ : (((PBINDING_CONTEXT)(pBinding))->pAdapterContext->NdisMedium == NdisMediumFddi) \ ? 14 \ : ((PBINDING_CONTEXT)(pBinding))->pAdapterContext->RcvLanHeaderLength) #else // // this always returns 14 as the DIX lan header length // #define LlcGetReceivedLanHeaderLength(pBinding) \ ((((PBINDING_CONTEXT)(pBinding))->pAdapterContext->NdisMedium == NdisMedium802_3) \ ? 14 \ : (((PBINDING_CONTEXT)(pBinding))->pAdapterContext->NdisMedium == NdisMediumFddi) \ ? 14 \ : ((PBINDING_CONTEXT)(pBinding))->pAdapterContext->RcvLanHeaderLength) #endif // // USHORT // LlcGetEthernetType( // IN PVOID hContext // ); // #define LlcGetEthernetType(hContext) \ (((PBINDING_CONTEXT)(hContext))->pAdapterContext->EthernetType) // // UINT // LlcGetCommittedSpace( // IN PVOID hLink // ); // #define LlcGetCommittedSpace(hLink) \ (((PDATA_LINK)(hLink))->BufferCommitment) #else // // separation of church and state, or DLC and LLC even // UINT LlcGetReceivedLanHeaderLength( IN PVOID pBinding ); USHORT LlcGetEthernetType( IN PVOID hContext ); UINT LlcGetCommittedSpace( IN PVOID hLink ); #endif // DLC_AND_LLC #endif // _LLC_API_