/*++ Copyright (c) 1991 Microsoft Corporation Module Name: llcmain.c Abstract: This module implements data link object for NDIS 3.0. Data link driver provides 802.2 LLC Class I and II services and also interface to send and receive direct network data. This module may later be used as general packet router for the protocol modules => smaller system overhead, when the NDIS packet header is checked only once. LLC interface is also much easier to use than NDIS. Its main tasks are: - implement simple and realiable LLC Class II connection-oriented services for the other drivers - provide network independent interface 802.2 interface - remove the system overhead of the packet and indication routing to all protocol modules - provide transmit packet queueing for the protocol drivers - provide 802.2 compatible connect, disconnect and close services, that calls back, when the transmit queue is empty. The services provides the module are somewhat extended 802.2 services, because the protocol engine is a IBM version of ISO-HDLC ABM. LlcDisconnet and LlcConnect primitives implements both Request and Confirm of Connect/Disconnect Data link driver does not make any buffering for the data. All data buffer except the LLC header and lan header with the I-frames must be provided by the calling protocol driver. *********************** SPINLOCK RULES ************************* DataLink driver uses extensively several spin locks to make it as re-entrant as possible with multiple processors and to minimize unnecessary spin locking calls. The main problem with multiple spin locks are the dead locks. The spin locks must always be acquired the same order (and released in a reverse order): This is the order used with DataLink spin locks: 1. Adapter->ObjectDataBase Protects objects from close/delete. This is always locked in the receive indication routine. 2. Link->SpinLock Protects the link. This lock is needed to prevent to upper protocol to call the link station, when we are changing it state. SendSpinLock cannot protect it, because it must be switched off, when the pending commands are executed. (But could we keep SendSpinLock locked, when the transmit commands are completed). There will occure a dead lock in any way, if the upper protocol is waiting the last transmit to complete before it disconnects a link station. 3. Adapter->SendSpinLock // protects queues and packet pools --- Timer spin locks is used only by timer servives: 4. TimerSpinLock // protects the timer queues **************************************************************** Contents: LlcInitialize LlcTerminate Author: Antti Saarenheimo (o-anttis) 17-MAY-1991 Revision History: --*/ // // This define enables the private DLC function prototypes // We don't want to export our data types to the dlc layer. // MIPS compiler doesn't accept hiding of the internal data // structures by a PVOID in the function prototype. // i386 will check the type defines // #ifndef i386 #define LLC_PUBLIC_NDIS_PROTOTYPES #endif #include #include "dbgmsg.h" // // These are the defaults defined in the IBM LAN Architecture reference, // this may be set by a DLC application, if it want to change the defaults. // DLC_LINK_PARAMETERS DefaultParameters = { 3, // T1 600 milliseconds (3 * 5 * 40) 2, // T2 80 milliseconds (2 * 1 * 40) 10, // Ti 25 seconds ((10 - 5) * 125 * 4) 127, // TW: maximum transmit window size 127, // RW: The maximum receive window size 20, // Nw: number of LPDUs acknowledged, before Ww is incr.) 5, // N2: Number of retires allowed (both Polls and I LPDSs) 0, // lowest proirity by default 600 // default for info field length by default }; KMUTEX NdisAccessMutex; KSEMAPHORE OpenAdapterSemaphore; #define LLC_PROTOCOL_NAME L"DLC" #ifdef NDIS40 extern ULONG gWaitForAdapter; #endif // NDIS40 DLC_STATUS LlcInitialize( VOID ) /*++ Routine Description: The routines initializes the protocol module and does the minimal stuff, that must be done in the serialized initialization routine. Arguments: None. Return Value: NDIS_STATUS --*/ { NDIS_STATUS Status; NDIS_PROTOCOL_CHARACTERISTICS LlcChars; ASSUME_IRQL(PASSIVE_LEVEL); // // We must build a MDL for the XID information used // when the link level takes care of XID handling. // pXidMdl = IoAllocateMdl(&Ieee802Xid, sizeof(Ieee802Xid), FALSE, FALSE, NULL ); if (pXidMdl == NULL) { return DLC_STATUS_NO_MEMORY; } #ifdef NDIS40 // // Event to signal all adapters have been bound - OK for LlcOpenAdapter // to bind. // NdisInitializeEvent(&PnPBindsComplete); NdisResetEvent(&PnPBindsComplete); #endif // NDIS40 #if LLC_DBG ALLOCATE_SPIN_LOCK(&MemCheckLock); #endif MmBuildMdlForNonPagedPool(pXidMdl); LlcInitializeTimerSystem(); NdisZeroMemory(&LlcChars, sizeof(LlcChars)); NdisInitUnicodeString(&LlcChars.Name, LLC_PROTOCOL_NAME); #ifdef NDIS40 LlcChars.MajorNdisVersion = 4; LlcChars.MinorNdisVersion = 0; LlcChars.OpenAdapterCompleteHandler = LlcNdisOpenAdapterComplete; LlcChars.CloseAdapterCompleteHandler = LlcNdisCloseComplete; LlcChars.SendCompleteHandler = LlcNdisSendComplete; LlcChars.TransferDataCompleteHandler = LlcNdisTransferDataComplete; LlcChars.ResetCompleteHandler = LlcNdisResetComplete; LlcChars.RequestCompleteHandler = LlcNdisRequestComplete; LlcChars.ReceiveHandler = LlcNdisReceiveIndication; LlcChars.ReceiveCompleteHandler = LlcNdisReceiveComplete; LlcChars.StatusHandler = NdisStatusHandler; LlcChars.StatusCompleteHandler = LlcNdisReceiveComplete; // DLC supports bind/unbind/pnp, but not unload. LlcChars.UnloadHandler = NULL; LlcChars.PnPEventHandler = LlcPnPEventHandler; LlcChars.BindAdapterHandler = LlcBindAdapterHandler; LlcChars.UnbindAdapterHandler = LlcUnbindAdapterHandler; // // Need to get value for waiting on uninitialized adapters. // if (!NT_SUCCESS(GetAdapterWaitTimeout(&gWaitForAdapter))) { ASSERT(FALSE); gWaitForAdapter = 15; // Default. } DEBUGMSG(DBG_WARN, (TEXT("WaitForAdapter delay = %d sec\n"), gWaitForAdapter)); #else // NDIS40 LlcChars.MajorNdisVersion = 3; LlcChars.MinorNdisVersion = 0; LlcChars.OpenAdapterCompleteHandler = LlcNdisOpenAdapterComplete; LlcChars.CloseAdapterCompleteHandler = LlcNdisCloseComplete; LlcChars.SendCompleteHandler = LlcNdisSendComplete; LlcChars.TransferDataCompleteHandler = LlcNdisTransferDataComplete; LlcChars.ResetCompleteHandler = LlcNdisResetComplete; LlcChars.RequestCompleteHandler = LlcNdisRequestComplete; LlcChars.ReceiveHandler = LlcNdisReceiveIndication; LlcChars.ReceiveCompleteHandler = LlcNdisReceiveComplete; LlcChars.StatusHandler = NdisStatusHandler; LlcChars.StatusCompleteHandler = LlcNdisReceiveComplete; #endif // !NDIS40 NdisRegisterProtocol(&Status, &LlcProtocolHandle, &LlcChars, sizeof(LlcChars)); KeInitializeSpinLock(&LlcSpinLock); ASSUME_IRQL(PASSIVE_LEVEL); KeInitializeMutex(&NdisAccessMutex, 1); // // We use the OpenAdapterSemaphore in the LlcOpenAdapter function. We really // want a mutex, but a mutex causes us problems on a checked build if we // make a call into NTOS. In either case, we just need a mechanism to ensure // only one thread is creating the ADAPTER_CONTEXT & opening the adapter at // NDIS level // KeInitializeSemaphore(&OpenAdapterSemaphore, 1, 1); if (Status != STATUS_SUCCESS) { IoFreeMdl(pXidMdl); } return Status; } VOID LlcTerminate( VOID ) /*++ Routine Description: The routines terminates the LLC protocol module and frees its global resources. This assumes all adapter bindings to be closed. Arguments: None. Return Value: None. --*/ { NDIS_STATUS Status; ASSUME_IRQL(PASSIVE_LEVEL); DEBUGMSG(DBG_INIT, (TEXT("+LlcTerminate()\n"))); LlcTerminateTimerSystem(); #ifdef NDIS40 CloseAllAdapters(); #endif // NDIS40 NdisDeregisterProtocol(&Status, LlcProtocolHandle); IoFreeMdl(pXidMdl); }