/***************************************************************************** * * Copyright (c) 1996 Microsoft Corporation * * Module: irndis.c * * Author: mbert 8-96 * * This modules provides the MAC interface of IrLAP (formerly IrMAC * of Pegasus). It is now an Ndis protocol interface for communicating * with Miniport Ir framers. * * |---------| * | | * | IrLAP | * | | * |---------| * /|\ | * | | * IrlapUp(IrlapContext, | | IrmacDown(LinkContext, * IrdaMsg) | | IrdaMsg) * | | * | \|/ * |----------| * | | * | IrNDIS | * | | * |----------| * /|\ | * | | Ndis Interface for transports * | | * | \|/ * |---------------------------| * | Ndis Wrapper | * |---------------------------| * |------------| * | | * | Miniport | * | Framer | * | | * |------------| * * * * */ #include #include #include #include #include #include #include #include #include #undef offsetof #include "irndis.tmh" #define WORK_BUF_SIZE 256 #define NICK_NAME_LEN 18 #define DISABLE_CODE_PAGING 1 #define DISABLE_DATA_PAGING 2 #ifdef ALLOC_DATA_PRAGMA #pragma data_seg("PAGE") #endif NDIS_HANDLE NdisIrdaHandle; // Handle to identify Irda to Ndis // when opening adapters UINT DisconnectTime; // WARNING: This variable is used // to lock down all pageable data // (see MmLockPageDataSection below) UINT HintCharSet; UINT Slots; UCHAR NickName[NICK_NAME_LEN + 1]; UINT NickNameLen; UINT MaxWindow; UINT NoCopyCnt; UINT CopyCnt; extern VOID (*CloseRasIrdaAddresses)(); #ifdef ALLOC_DATA_PRAGMA #pragma data_seg() #endif typedef struct _IRDA_REQUEST { NDIS_REQUEST NdisRequest; NDIS_STATUS Status; NDIS_EVENT Event; } IRDA_REQUEST, *PIRDA_REQUEST; VOID OidToLapQos( const UINT ParmTable[], UINT ValArray[], UINT Cnt, PUINT pBitField, BOOLEAN MaxVal); NDIS_STATUS IrdaQueryOid( IN PIRDA_LINK_CB pIrdaLinkCb, IN NDIS_OID Oid, OUT PUINT pQBuf, IN OUT PUINT pQBufLen); NDIS_STATUS IrdaSetOid( IN PIRDA_LINK_CB pIrdaLinkCb, IN NDIS_OID Oid, IN UINT Val); VOID IrdaSendComplete( IN NDIS_HANDLE Context, IN PNDIS_PACKET NdisPacket, IN NDIS_STATUS Status ); VOID InitializeLocalQos( IN OUT IRDA_QOS_PARMS *pQos, IN PNDIS_STRING ConfigPath); VOID IrdaBindAdapter( OUT PNDIS_STATUS pStatus, IN NDIS_HANDLE BindContext, IN PNDIS_STRING AdapterName, IN PVOID SystemSpecific1, IN PVOID SystemSpecific2); VOID MacControlRequest( PIRDA_LINK_CB pIrdaLinkCb, PIRDA_MSG pMsg); VOID ConfirmDataRequest( PIRDA_LINK_CB pIrdaLinkCb, PIRDA_MSG pMsg); VOID MediaSenseExp(PVOID Context); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, IrdaInitialize) #pragma alloc_text(PAGEIRDA, OidToLapQos) // WARNING: This function is used // to lock all paged code down // (see MmLockPagableCodeSection // below) #pragma alloc_text(PAGEIRDA, IrdaQueryOid) #pragma alloc_text(PAGEIRDA, IrdaSetOid) #pragma alloc_text(PAGEIRDA, MacControlRequest) #pragma alloc_text(PAGEIRDA, MediaSenseExp) #pragma alloc_text(PAGEIRDA, InitializeLocalQos) #endif _inline VOID DBG_FRAME( PIRDA_LINK_CB pIrdaLinkCb, BOOLEAN Transmit, UCHAR *pFrame, UINT HdrLen, UINT DataLen) { LARGE_INTEGER li; int CurrTime, Diff, Inc; Inc = KeQueryTimeIncrement(); KeQueryTickCount(&li); CurrTime = (int) li.LowPart * Inc; Diff = CurrTime - pIrdaLinkCb->LastTime; pIrdaLinkCb->LastTime = CurrTime; if ((WPP_LEVEL_ENABLED(DBG_TXFRAME) && Transmit) || (WPP_LEVEL_ENABLED(DBG_RXFRAME) && !Transmit)) { UCHAR StrBuf[256]; int FrameType; DecodeIRDA(&FrameType, pFrame, HdrLen, StrBuf, sizeof(StrBuf), 0, TRUE, 1); if (Transmit) { DEBUGMSG(DBG_TXFRAME, ("%03d %s %s len:%d\n", Diff/10000, "Tx:", (char*)StrBuf, DataLen)); } else { DEBUGMSG(DBG_RXFRAME, ("%03d %s %s len:%d\n", Diff/10000, "Rx:", (char*)StrBuf, DataLen)); } } } /*************************************************************************** * * Translate the result of an OID query to IrLAP QOS definition * */ VOID OidToLapQos( const UINT ParmTable[], UINT ValArray[], UINT Cnt, PUINT pBitField, BOOLEAN MaxVal) { UINT i, j; PAGED_CODE(); *pBitField = 0; for (i = 0; i < Cnt; i++) { for (j = 0; j <= PV_TABLE_MAX_BIT; j++) { if (ValArray[i] == ParmTable[j]) { *pBitField |= 1<NdisBindingHandle, &Request.NdisRequest); if (Status == NDIS_STATUS_PENDING) { NdisWaitEvent(&Request.Event, 0); Status = Request.Status; } *pQBufLen = Request.NdisRequest.DATA.QUERY_INFORMATION.BytesWritten / sizeof(UINT); return Status; } /*************************************************************************** * * Perform a synchronous request to sent an OID * */ NDIS_STATUS IrdaSetOid( IN PIRDA_LINK_CB pIrdaLinkCb, IN NDIS_OID Oid, IN UINT Val) { IRDA_REQUEST Request; NDIS_STATUS Status; PAGED_CODE(); NdisInitializeEvent(&Request.Event); NdisResetEvent(&Request.Event); Request.NdisRequest.RequestType = NdisRequestSetInformation; Request.NdisRequest.DATA.SET_INFORMATION.Oid = Oid; Request.NdisRequest.DATA.SET_INFORMATION.InformationBuffer = &Val; Request.NdisRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(UINT); NdisRequest(&Status, pIrdaLinkCb->NdisBindingHandle, &Request.NdisRequest); if (Status == NDIS_STATUS_PENDING) { NdisWaitEvent(&Request.Event, 0); Status = Request.Status; } return Status; } /*************************************************************************** * * Allocate an Irda message for IrLap to use for control frames. * This modules owns these so IrLAP doesn't have to deal with the * Ndis send complete. * */ IRDA_MSG * AllocTxMsg(PIRDA_LINK_CB pIrdaLinkCb) { IRDA_MSG *pMsg; pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->TxMsgFreeList, &pIrdaLinkCb->SpinLock); if (pMsg == NULL) { if (pIrdaLinkCb->TxMsgFreeListLen > 10) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: too many tx msgs\n"))); return NULL; } NdisAllocateMemoryWithTag(&pMsg, sizeof(IRDA_MSG) + IRDA_MSG_DATA_SIZE, MT_IRNDIS_TX_IMSG); if (pMsg == NULL) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: Aloc tx msg failed\n"))); return NULL; } pIrdaLinkCb->TxMsgFreeListLen++; } // Indicate driver owns message pMsg->IRDA_MSG_pOwner = &pIrdaLinkCb->TxMsgFreeList; // Initialize pointers pMsg->IRDA_MSG_pHdrWrite = \ pMsg->IRDA_MSG_pHdrRead = pMsg->IRDA_MSG_Header + IRDA_HEADER_LEN; pMsg->IRDA_MSG_pBase = \ pMsg->IRDA_MSG_pRead = \ pMsg->IRDA_MSG_pWrite = (UCHAR *) pMsg + sizeof(IRDA_MSG); pMsg->IRDA_MSG_pLimit = pMsg->IRDA_MSG_pBase + IRDA_MSG_DATA_SIZE-1; return pMsg; } /*************************************************************************** * * */ #if DBG VOID CleanupRxMsgList( PIRDA_LINK_CB pIrdaLinkCb, BOOLEAN LinkClose) #else VOID CleanupRxMsgList( PIRDA_LINK_CB pIrdaLinkCb) #endif { PIRDA_MSG pMsg, pMsgNext; NdisAcquireSpinLock(&pIrdaLinkCb->SpinLock); for (pMsg = (PIRDA_MSG) pIrdaLinkCb->RxMsgList.Flink; pMsg != (PIRDA_MSG) &pIrdaLinkCb->RxMsgList; pMsg = pMsgNext) { pMsgNext = (PIRDA_MSG) pMsg->Linkage.Flink; if (pMsg->Prim == MAC_DATA_IND) { RemoveEntryList(&pMsg->Linkage); pMsg->Prim = MAC_DATA_RESP; NdisReleaseSpinLock(&pIrdaLinkCb->SpinLock); IrmacDown(pIrdaLinkCb, pMsg); NdisAcquireSpinLock(&pIrdaLinkCb->SpinLock); #if DBG if (!LinkClose) { ++pIrdaLinkCb->DelayedRxFrameCnt; } #endif } else { DbgPrint("IRNDIS: MAC_DATA_CONF on RxMsgList, not completing!\n"); } } NdisReleaseSpinLock(&pIrdaLinkCb->SpinLock); } /*************************************************************************** * * Process MAC_CONTROL_REQs from IrLAP * */ VOID MacControlRequest( PIRDA_LINK_CB pIrdaLinkCb, PIRDA_MSG pMsg) { NDIS_STATUS Status; PAGED_CODE(); switch (pMsg->IRDA_MSG_Op) { case MAC_INITIALIZE_LINK: case MAC_RECONFIG_LINK: pIrdaLinkCb->ExtraBofs = pMsg->IRDA_MSG_NumBOFs; pIrdaLinkCb->MinTat = pMsg->IRDA_MSG_MinTat; Status = IrdaSetOid(pIrdaLinkCb, OID_IRDA_LINK_SPEED, (UINT) pMsg->IRDA_MSG_Baud); return; case MAC_MEDIA_SENSE: pIrdaLinkCb->MediaBusy = FALSE; IrdaSetOid(pIrdaLinkCb, OID_IRDA_MEDIA_BUSY, 0); pIrdaLinkCb->MediaSenseTimer.Timeout = pMsg->IRDA_MSG_SenseTime; IrdaTimerStart(&pIrdaLinkCb->MediaSenseTimer); return; case MAC_CLOSE_LINK: DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: Closelink %p\n"), pIrdaLinkCb)); IrdaTimerStop(&pIrdaLinkCb->MediaSenseTimer); NdisResetEvent(&pIrdaLinkCb->OpenCloseEvent); #ifdef IRDA_RX_SYSTEM_THREAD KeSetEvent(&pIrdaLinkCb->EvKillRxThread, 0, FALSE); #endif #if DBG CleanupRxMsgList(pIrdaLinkCb, TRUE); #else CleanupRxMsgList(pIrdaLinkCb); #endif NdisCloseAdapter(&Status, pIrdaLinkCb->NdisBindingHandle); if (Status == NDIS_STATUS_PENDING) { NdisWaitEvent(&pIrdaLinkCb->OpenCloseEvent, 0); Status = pIrdaLinkCb->OpenCloseStatus; } if (pIrdaLinkCb->UnbindContext != NULL) { NdisCompleteUnbindAdapter(pIrdaLinkCb->UnbindContext, NDIS_STATUS_SUCCESS); DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: NdisCompleteUndindAdapter for link %p called\n"), pIrdaLinkCb)); } REFDEL(&pIrdaLinkCb->RefCnt, 'DNIB'); return; } ASSERT(0); } VOID ConfirmDataRequest( PIRDA_LINK_CB pIrdaLinkCb, PIRDA_MSG pMsg) { if (pMsg->IRDA_MSG_pOwner == &pIrdaLinkCb->TxMsgFreeList) { // If TxMsgFreeList is the owner, then this is a control // frame which isn't confirmed. NdisInterlockedInsertTailList(&pIrdaLinkCb->TxMsgFreeList, &pMsg->Linkage, &pIrdaLinkCb->SpinLock); return; } ASSERT(pMsg->IRDA_MSG_RefCnt); if (InterlockedDecrement(&pMsg->IRDA_MSG_RefCnt) == 0) { pMsg->Prim = MAC_DATA_CONF; NdisInterlockedInsertTailList(&pIrdaLinkCb->RxMsgList, &pMsg->Linkage, &pIrdaLinkCb->SpinLock); #ifdef IRDA_RX_SYSTEM_THREAD KeSetEvent(&pIrdaLinkCb->EvRxMsgReady, 0, FALSE); #else IrdaEventSchedule(&pIrdaLinkCb->EvRxMsgReady, pIrdaLinkCb); #endif } } /*************************************************************************** * * Process control and data requests from IrLAP * */ VOID IrmacDown( IN PVOID Context, PIRDA_MSG pMsg) { NDIS_STATUS Status; PNDIS_PACKET NdisPacket = NULL; PNDIS_BUFFER NdisBuffer = NULL; PIRDA_PROTOCOL_RESERVED pReserved; PNDIS_IRDA_PACKET_INFO IrdaPacketInfo; PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context; DEBUGMSG(DBG_FUNCTION, (TEXT("IrmacDown()\n"))); switch (pMsg->Prim) { case MAC_CONTROL_REQ: MacControlRequest(pIrdaLinkCb, pMsg); return; case MAC_DATA_RESP: // A data response from IrLAP is the mechanism used to // return ownership of received packets back to Ndis if (pMsg->DataContext) { DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: return packet %p\n"), pMsg->DataContext)); NdisReturnPackets(&((PNDIS_PACKET)pMsg->DataContext), 1); } NdisInterlockedInsertTailList(&pIrdaLinkCb->RxMsgFreeList, &pMsg->Linkage, &pIrdaLinkCb->SpinLock); pIrdaLinkCb->RxMsgFreeListLen++; return; case MAC_DATA_REQ: Status = NDIS_STATUS_FAILURE; // IrDA is half duplex. If there is something on the // receive list when we go to transmit then something // went very wrong (delay in the miniport somewhere). // Return these frames back to the miniport. #if DBG CleanupRxMsgList(pIrdaLinkCb, FALSE); #else CleanupRxMsgList(pIrdaLinkCb); #endif if (pIrdaLinkCb->UnbindContext || pIrdaLinkCb->LowPowerSt) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: Dropping MAC_DATA_REQ, link closing or low power state\n"))); goto Cleanup; } pReserved = (PIRDA_PROTOCOL_RESERVED) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->PacketList, &pIrdaLinkCb->SpinLock); if (pReserved == NULL) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: NdisPacket pool has been depleted\n"))); goto Cleanup; } NdisPacket = CONTAINING_RECORD(pReserved, NDIS_PACKET, ProtocolReserved); ASSERT(pMsg->IRDA_MSG_pHdrWrite-pMsg->IRDA_MSG_pHdrRead); // Allocate buffer for frame header NdisAllocateBuffer(&Status, &NdisBuffer, pIrdaLinkCb->BufferPool, pMsg->IRDA_MSG_pHdrRead, (UINT) (pMsg->IRDA_MSG_pHdrWrite-pMsg->IRDA_MSG_pHdrRead)); if (Status != NDIS_STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: NdisAllocateBuffer failed\n"))); ASSERT(0); goto Cleanup; } NdisChainBufferAtFront(NdisPacket, NdisBuffer); // if frame contains data, alloc buffer for data if (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead) { NdisAllocateBuffer(&Status, &NdisBuffer, pIrdaLinkCb->BufferPool, pMsg->IRDA_MSG_pRead, (UINT) (pMsg->IRDA_MSG_pWrite-pMsg->IRDA_MSG_pRead)); if (Status != NDIS_STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: NdisAllocateBuffer failed\n"))); ASSERT(0); goto Cleanup; } NdisChainBufferAtBack(NdisPacket, NdisBuffer); } pReserved = (PIRDA_PROTOCOL_RESERVED)(NdisPacket->ProtocolReserved); pReserved->pMsg = pMsg; IrdaPacketInfo = (PNDIS_IRDA_PACKET_INFO) \ (pReserved->MediaInfo.ClassInformation); IrdaPacketInfo->ExtraBOFs = pIrdaLinkCb->ExtraBofs; #if DBG_TIMESTAMP { LARGE_INTEGER li; KeQueryTickCount(&li); pReserved->TimeStamp[0] = (int) li.LowPart * KeQueryTimeIncrement(); } #endif if (pIrdaLinkCb->WaitMinTat) { IrdaPacketInfo->MinTurnAroundTime = pIrdaLinkCb->MinTat; pIrdaLinkCb->WaitMinTat = FALSE; } else { IrdaPacketInfo->MinTurnAroundTime = 0; } NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO( NdisPacket, &pReserved->MediaInfo, sizeof(MEDIA_SPECIFIC_INFORMATION) -1 + sizeof(NDIS_IRDA_PACKET_INFO)); DBG_FRAME( pIrdaLinkCb, TRUE, //DBG_TXFRAME, pMsg->IRDA_MSG_pHdrRead, (UINT) (pMsg->IRDA_MSG_pHdrWrite-pMsg->IRDA_MSG_pHdrRead), (UINT) ((pMsg->IRDA_MSG_pHdrWrite-pMsg->IRDA_MSG_pHdrRead) + (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead)) - IRLAP_HEADER_LEN); InterlockedIncrement(&pIrdaLinkCb->SendOutCnt); #if DBG { ULONG PacketLength; NdisQueryPacket(NdisPacket,NULL,NULL,NULL,&PacketLength); ASSERT(PacketLength <= 2048); } #endif DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: NdisSend(%p)\n outstaning %d"), NdisPacket,pIrdaLinkCb->SendOutCnt)); NdisSendPackets( pIrdaLinkCb->NdisBindingHandle, &NdisPacket, 1 ); return; default: ASSERT(0); return; } return; Cleanup: ConfirmDataRequest(pIrdaLinkCb, pMsg); if (NdisPacket != NULL) { NdisUnchainBufferAtFront(NdisPacket, &NdisBuffer); while (NdisBuffer) { NdisFreeBuffer(NdisBuffer); NdisUnchainBufferAtFront(NdisPacket, &NdisBuffer); } NdisReinitializePacket(NdisPacket); NdisInterlockedInsertTailList(&pIrdaLinkCb->PacketList, &pReserved->Linkage, &pIrdaLinkCb->SpinLock); } } /*************************************************************************** * * Callback for media sense timer expirations * */ VOID MediaSenseExp(PVOID Context) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context; IRDA_MSG IMsg; UINT MediaBusy; UINT Cnt = 1; PAGED_CODE(); IMsg.Prim = MAC_CONTROL_CONF; IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE; IMsg.IRDA_MSG_OpStatus = MAC_MEDIA_BUSY; if (pIrdaLinkCb->MediaBusy == FALSE) { if (IrdaQueryOid(pIrdaLinkCb, OID_IRDA_MEDIA_BUSY, &MediaBusy, &Cnt) == NDIS_STATUS_SUCCESS && !MediaBusy) { IMsg.IRDA_MSG_OpStatus = MAC_MEDIA_CLEAR; } } LOCK_LINK(pIrdaLinkCb); IrlapUp(pIrdaLinkCb->IrlapContext, &IMsg); UNLOCK_LINK(pIrdaLinkCb); } /*************************************************************************** * * Protocol open adapter complete handler * */ VOID IrdaOpenAdapterComplete( IN NDIS_HANDLE IrdaBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus ) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext; DEBUGMSG(DBG_NDIS, (TEXT("+IrdaOpenAdapterComplete() BindingContext %p, Status %x\n"), IrdaBindingContext, Status)); pIrdaLinkCb->OpenCloseStatus = Status; NdisSetEvent(&pIrdaLinkCb->OpenCloseEvent); DEBUGMSG(DBG_NDIS, (TEXT("-IrdaOpenAdapterComplete()\n"))); return; } /*************************************************************************** * * Protocol close adapter complete handler * */ VOID IrdaCloseAdapterComplete( IN NDIS_HANDLE IrdaBindingContext, IN NDIS_STATUS Status ) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext; DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: IrdaCloseAdapterComplete()\n"))); pIrdaLinkCb->OpenCloseStatus = Status; NdisSetEvent(&pIrdaLinkCb->OpenCloseEvent); return; } /*************************************************************************** * * Protocol send complete handler * */ VOID IrdaSendComplete( IN NDIS_HANDLE Context, IN PNDIS_PACKET NdisPacket, IN NDIS_STATUS Status ) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context; PIRDA_PROTOCOL_RESERVED pReserved = \ (PIRDA_PROTOCOL_RESERVED) NdisPacket->ProtocolReserved; PIRDA_MSG pMsg = pReserved->pMsg; PNDIS_BUFFER NdisBuffer; #if DBG_TIMESTAMP LARGE_INTEGER li; #endif //ASSERT(Status == NDIS_STATUS_SUCCESS); DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: IrdaSendComplete(%p) outstanding %d\n"), NdisPacket,pIrdaLinkCb->SendOutCnt-1)); ConfirmDataRequest(pIrdaLinkCb, pMsg); #if DBG_TIMESTAMP KeQueryTickCount(&li); pReserved->TimeStamp[1] = (int) li.LowPart * KeQueryTimeIncrement(); DEBUGMSG(1, (TEXT("C: %d\n"), (pReserved->TimeStamp[1] - pReserved->TimeStamp[0])/10000)); #endif if (NdisPacket) { NdisUnchainBufferAtFront(NdisPacket, &NdisBuffer); while (NdisBuffer) { NdisFreeBuffer(NdisBuffer); NdisUnchainBufferAtFront(NdisPacket, &NdisBuffer); } NdisReinitializePacket(NdisPacket); NdisInterlockedInsertTailList(&pIrdaLinkCb->PacketList, &pReserved->Linkage, &pIrdaLinkCb->SpinLock); } InterlockedDecrement(&pIrdaLinkCb->SendOutCnt); ASSERT(pIrdaLinkCb->SendOutCnt >= 0); NdisAcquireSpinLock(&pIrdaLinkCb->SpinLock); if (pIrdaLinkCb->SendOutCnt == 0 && pIrdaLinkCb->pNetPnpEvent) { PNET_PNP_EVENT pNetPnpEvent; ASSERT(pIrdaLinkCb->LowPowerSt == TRUE); pNetPnpEvent = pIrdaLinkCb->pNetPnpEvent; pIrdaLinkCb->pNetPnpEvent = NULL; NdisReleaseSpinLock(&pIrdaLinkCb->SpinLock); DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: Completing set power async\n"))); NdisCompletePnPEvent( NDIS_STATUS_SUCCESS, pIrdaLinkCb->NdisBindingHandle, pNetPnpEvent); } else { NdisReleaseSpinLock(&pIrdaLinkCb->SpinLock); } return; } /*************************************************************************** * * Protocol transfer complete handler * */ VOID IrdaTransferDataComplete( IN NDIS_HANDLE IrdaBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status, IN UINT BytesTransferred ) { DEBUGMSG(DBG_NDIS, (TEXT("+IrdaTransferDataComplete()\n"))); ASSERT(0); return; } /*************************************************************************** * * Protocol reset complete handler * */ void IrdaResetComplete( IN NDIS_HANDLE IrdaBindingContext, IN NDIS_STATUS Status ) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext; DEBUGMSG(DBG_ERROR, (TEXT("+IrdaResetComplete()\n"))); NdisSetEvent(&pIrdaLinkCb->ResetEvent); return; } /*************************************************************************** * * Protocol request complete handler * */ void IrdaRequestComplete( IN NDIS_HANDLE IrdaBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status ) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext; PIRDA_REQUEST Request=CONTAINING_RECORD(NdisRequest,IRDA_REQUEST,NdisRequest); //DEBUGMSG(DBG_NDIS, (TEXT("+IrdaRequestComplete()\n"))); Request->Status = Status; NdisSetEvent(&Request->Event); return; } /*************************************************************************** * * Protocol receive handler - This asserts if I don't get all data in the * lookahead buffer. * */ NDIS_STATUS IrdaReceive( IN NDIS_HANDLE IrdaBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) { DEBUGMSG(DBG_NDIS, (TEXT("+IrdaReceive()\n"))); DEBUGMSG(DBG_ERROR, (TEXT("ProtocolReceive is not supported by irda\n"))); ASSERT(0); return NDIS_STATUS_NOT_ACCEPTED; } /*************************************************************************** * * Protocol receive complete handler - what is this for? * */ VOID IrdaReceiveComplete( IN NDIS_HANDLE IrdaBindingContext ) { DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: IrdaReceiveComplete()\n"))); return; } /*************************************************************************** * * Protocol status handler * */ VOID IrdaStatus( IN NDIS_HANDLE IrdaBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferSize ) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext; if (GeneralStatus == NDIS_STATUS_MEDIA_BUSY) { DEBUGMSG(DBG_NDIS, (TEXT("STATUS_MEDIA_BUSY\n"))); pIrdaLinkCb->MediaBusy = TRUE; } else { DEBUGMSG(DBG_NDIS, (TEXT("Unknown Status indication\n"))); } return; } /*************************************************************************** * * Protocol status complete handler * */ VOID IrdaStatusComplete( IN NDIS_HANDLE IrdaBindingContext ) { DEBUGMSG(DBG_NDIS, (TEXT("IrdaStatusComplete()\n"))); return; } /*************************************************************************** * * RxThread - Hands received frames to Irlap for processing. This is * the callback of an exec worker thread running at passive level * which allows us to get a mutex in order to single thread * events through the stack. * OR * This is an actual system thread created a bind time that waits on * 2 events: * 1 - EvRxMsgReady, an inbound frame is ready on RxMsgList * 2 - EvKillRxThread * */ VOID RxThread(void *Arg) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Arg; PIRDA_MSG pMsg; BOOLEAN Done = FALSE; #ifdef IRDA_RX_SYSTEM_THREAD NTSTATUS Status; PKEVENT EventList[2] = {&pIrdaLinkCb->EvRxMsgReady, &pIrdaLinkCb->EvKillRxThread}; BOOLEAN DataIndication; KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); #endif while (!Done) { pMsg = (PIRDA_MSG) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->RxMsgList, &pIrdaLinkCb->SpinLock); while (pMsg) { if (pMsg->Prim == MAC_DATA_IND) { DataIndication = TRUE; pMsg->IRDA_MSG_RefCnt = 1; DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: Indicate packet %p\n"), pMsg->DataContext)); } else { DataIndication = FALSE; } LOCK_LINK(pIrdaLinkCb); IrlapUp(pIrdaLinkCb->IrlapContext, pMsg); UNLOCK_LINK(pIrdaLinkCb); if (DataIndication) { // // no protection needed for refcount cuz this // is the only thread that operates on it // ASSERT(pMsg->IRDA_MSG_RefCnt); pMsg->IRDA_MSG_RefCnt -= 1; if (pMsg->IRDA_MSG_RefCnt && pMsg->DataContext) { CopyCnt++; // Irlap had to hold the data because of missing // frames. Some miniports can't handle the stack // owning the frames for any length of time. DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: return packet %p\n"), pMsg->DataContext)); NdisReturnPackets(&((PNDIS_PACKET)pMsg->DataContext), 1); pMsg->DataContext = NULL; } else { NoCopyCnt++; } if (pMsg->IRDA_MSG_RefCnt == 0) { pMsg->Prim = MAC_DATA_RESP; IrmacDown(pIrdaLinkCb, pMsg); } } pMsg = (PIRDA_MSG) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->RxMsgList, &pIrdaLinkCb->SpinLock); } #ifdef IRDA_RX_SYSTEM_THREAD Status = KeWaitForMultipleObjects(2, EventList, WaitAny, Executive, KernelMode, FALSE, NULL, NULL); if (Status != 0) { if (Status != 1) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: KeWaitForMultObj return %X\n"), Status)); } DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: Terminating RxThread\n"))); PsTerminateSystemThread(STATUS_SUCCESS); } #else Done = TRUE; #endif } } /*************************************************************************** * * Protocol receive packet handler - Called at DPC, put the message on * RxList and have Exec worker thread process it at passive level. * */ INT IrdaReceivePacket( IN NDIS_HANDLE IrdaBindingContext, IN PNDIS_PACKET Packet) { UINT BufCnt, TotalLen, BufLen; PNDIS_BUFFER pNdisBuf; PIRDA_MSG pMsg; UCHAR *pData; PIRDA_LINK_CB pIrdaLinkCb = IrdaBindingContext; DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: IrdaReceivePacket(%p)\n"), Packet)); if (pIrdaLinkCb->UnbindContext) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: Ignoring received packet, link closing\n"))); return 0; } NdisQueryPacket(Packet, NULL, &BufCnt, &pNdisBuf, &TotalLen); if ((TotalLen < 2) || (TotalLen > (UINT)pIrdaLinkCb->RxMsgDataSize+1)) { // // all irda frames need an (A)ddress and (C)ontrol bytes, // // They also need to be small enough to fix in buffer at the end of the rx message // if the protocol needs to hang on to the packet. The buffers are allocated based on // the max packet size. The protocol only uses the data following the AC bytes so // we out buffers are actually two bytes bigger than needed. We add on byte onto // the allowable size since win2k had a bug that would cause it to send 2049 byte // packets. // DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: Frame less than two bytes or bigger than the max size %d\n"),TotalLen)); return 0; } ASSERT(BufCnt == 1); NdisQueryBufferSafe(pNdisBuf, &pData, &BufLen, NormalPagePriority); if (pData == NULL) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: NdisQueryBufferSafe failed\n"))); return 0; } pIrdaLinkCb->WaitMinTat = TRUE; pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->RxMsgFreeList, &pIrdaLinkCb->SpinLock); if (pMsg == NULL) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: RxMsgFreeList depleted!\n"))); return 0; } pIrdaLinkCb->RxMsgFreeListLen--; pMsg->Prim = MAC_DATA_IND; pMsg->IRDA_MSG_pRead = pData; pMsg->IRDA_MSG_pWrite = pData + BufLen; pMsg->DataContext = Packet; NdisInterlockedInsertTailList(&pIrdaLinkCb->RxMsgList, &pMsg->Linkage, &pIrdaLinkCb->SpinLock); DBG_FRAME(pIrdaLinkCb, FALSE, //DBG_RXFRAME, pMsg->IRDA_MSG_pRead, (UINT) (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead), (UINT) ((pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead)) - IRLAP_HEADER_LEN); #ifdef IRDA_RX_SYSTEM_THREAD KeSetEvent(&pIrdaLinkCb->EvRxMsgReady, 0, FALSE); #else IrdaEventSchedule(&pIrdaLinkCb->EvRxMsgReady, pIrdaLinkCb); #endif return 1; // Ownership reference count of packet } /*************************************************************************** * * Delete all control blocks for a given link * */ VOID DeleteIrdaLink(PVOID Arg) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Arg; int i; PIRDA_MSG pMsg; DEBUGMSG(DBG_IRMAC,("IRNDIS: Delete instance %p\n", pIrdaLinkCb)); NdisFreeBufferPool(pIrdaLinkCb->BufferPool); pIrdaLinkCb->BufferPool=NULL; for (i = 0; i < IRDA_NDIS_PACKET_POOL_SIZE; i++) { PIRDA_PROTOCOL_RESERVED pReserved; PNDIS_PACKET NdisPacket; pReserved = (PIRDA_PROTOCOL_RESERVED) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->PacketList, &pIrdaLinkCb->SpinLock); if (pReserved == NULL) { DEBUGMSG(DBG_ERROR, (TEXT("Not all NdisPackets were on list when deleting\n"))); ASSERT(0); break; } NdisPacket = CONTAINING_RECORD(pReserved, NDIS_PACKET, ProtocolReserved); NdisFreePacket(NdisPacket); } NdisFreePacketPool(pIrdaLinkCb->PacketPool); pIrdaLinkCb->PacketPool=NULL; pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->TxMsgFreeList, &pIrdaLinkCb->SpinLock); while (pMsg != NULL) { NdisFreeMemory(pMsg, sizeof(IRDA_MSG) + IRDA_MSG_DATA_SIZE, 0); pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->TxMsgFreeList, &pIrdaLinkCb->SpinLock); } pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->RxMsgFreeList, &pIrdaLinkCb->SpinLock); while (pMsg != NULL) { NdisFreeMemory(pMsg, sizeof(IRDA_MSG), 0); pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->RxMsgFreeList, &pIrdaLinkCb->SpinLock); } IrlapDeleteInstance(pIrdaLinkCb->IrlapContext); pIrdaLinkCb->IrlapContext=NULL; IrlmpDeleteInstance(pIrdaLinkCb->IrlmpContext); pIrdaLinkCb->IrlmpContext=NULL; NdisFreeSpinLock(&pIrdaLinkCb->SpinLock); NdisFreeMemory(pIrdaLinkCb, sizeof(IRDA_LINK_CB), 0); } /*************************************************************************** * * Initialize local Qos with info from adapters register and globals * initialized at driver entry time (from protocol's registery) * */ VOID InitializeLocalQos( IN OUT IRDA_QOS_PARMS *pQos, IN PNDIS_STRING ConfigPath) { NDIS_HANDLE ConfigHandle; NDIS_STRING DataSizeStr = NDIS_STRING_CONST("DATASIZE"); NDIS_STRING WindowSizeStr = NDIS_STRING_CONST("WINDOWSIZE"); NDIS_STRING MaxTatStr = NDIS_STRING_CONST("MAXTURNTIME"); NDIS_STRING BofsStr = NDIS_STRING_CONST("BOFS"); PNDIS_CONFIGURATION_PARAMETER ParmVal; NDIS_STATUS Status; PAGED_CODE(); pQos->bfDisconnectTime = DisconnectTime; pQos->bfDataSize = IRLAP_DEFAULT_DATASIZE; pQos->bfWindowSize = IRLAP_DEFAULT_WINDOWSIZE; pQos->bfMaxTurnTime = IRLAP_DEFAULT_MAXTAT; pQos->bfBofs = BOFS_0; NdisOpenProtocolConfiguration(&Status, &ConfigHandle, ConfigPath); if (Status == NDIS_STATUS_SUCCESS) { NdisReadConfiguration(&Status, &ParmVal, ConfigHandle, &DataSizeStr, NdisParameterInteger); if (Status == NDIS_STATUS_SUCCESS) pQos->bfDataSize = ParmVal->ParameterData.IntegerData; NdisReadConfiguration(&Status, &ParmVal, ConfigHandle, &WindowSizeStr, NdisParameterInteger); if (Status == NDIS_STATUS_SUCCESS) pQos->bfWindowSize = ParmVal->ParameterData.IntegerData; NdisReadConfiguration(&Status, &ParmVal, ConfigHandle, &MaxTatStr, NdisParameterInteger); if (Status == NDIS_STATUS_SUCCESS) pQos->bfMaxTurnTime = ParmVal->ParameterData.IntegerData; NdisReadConfiguration(&Status, &ParmVal, ConfigHandle, &BofsStr, NdisParameterInteger); if (Status == NDIS_STATUS_SUCCESS) pQos->bfBofs = ParmVal->ParameterData.IntegerData; NdisCloseConfiguration(ConfigHandle); } DEBUGMSG(DBG_NDIS, (TEXT("DataSize %x, WindowSize %x, MaxTat %x, Bofs=%x\n"), pQos->bfDataSize, pQos->bfWindowSize, pQos->bfMaxTurnTime,pQos->bfBofs)); } /*************************************************************************** * * Protocol bind adapter handler * */ VOID IrdaBindAdapter( OUT PNDIS_STATUS pStatus, IN NDIS_HANDLE BindContext, IN PNDIS_STRING AdapterName, IN PVOID SystemSpecific1, IN PVOID SystemSpecific2 ) { NDIS_STATUS OpenErrorStatus; NDIS_MEDIUM MediumArray[] = {NdisMediumIrda}; UINT SelectedMediumIndex; PIRDA_LINK_CB pIrdaLinkCb; UINT UintArray[16]; UINT UintArrayCnt; IRDA_MSG *pMsg; int i, WinSize; IRDA_QOS_PARMS LocalQos; UCHAR DscvInfoBuf[64]; int DscvInfoLen; ULONG Val, Mask; NDIS_STATUS CloseStatus; ULONG BytesToCopy; #ifdef IRDA_RX_SYSTEM_THREAD HANDLE hSysThread; #endif DEBUGMSG(DBG_IRMAC, (TEXT("IRNDIS: IrdaBindAdapter() \"%ws\"\n"), AdapterName->Buffer)); NdisAllocateMemoryWithTag((PVOID *)&pIrdaLinkCb, sizeof(IRDA_LINK_CB), MT_IRNDIS_LINKCB); if (!pIrdaLinkCb) { *pStatus = STATUS_INSUFFICIENT_RESOURCES; goto exit10; } NdisZeroMemory(pIrdaLinkCb, sizeof(IRDA_LINK_CB)); ReferenceInit(&pIrdaLinkCb->RefCnt, pIrdaLinkCb, DeleteIrdaLink); REFADD(&pIrdaLinkCb->RefCnt, 'DNIB'); pIrdaLinkCb->UnbindContext = NULL; pIrdaLinkCb->WaitMinTat = FALSE; pIrdaLinkCb->PnpContext = SystemSpecific2; NdisInitializeEvent(&pIrdaLinkCb->OpenCloseEvent); NdisResetEvent(&pIrdaLinkCb->OpenCloseEvent); NdisInitializeEvent(&pIrdaLinkCb->ResetEvent); NdisResetEvent(&pIrdaLinkCb->ResetEvent); NdisAllocateSpinLock(&pIrdaLinkCb->SpinLock); INIT_LINK_LOCK(pIrdaLinkCb); NdisInitializeListHead(&pIrdaLinkCb->TxMsgFreeList); NdisInitializeListHead(&pIrdaLinkCb->RxMsgFreeList); NdisInitializeListHead(&pIrdaLinkCb->RxMsgList); #ifdef IRDA_RX_SYSTEM_THREAD KeInitializeEvent(&pIrdaLinkCb->EvRxMsgReady, SynchronizationEvent, FALSE); KeInitializeEvent(&pIrdaLinkCb->EvKillRxThread, SynchronizationEvent, FALSE); #else IrdaEventInitialize(&pIrdaLinkCb->EvRxMsgReady, RxThread); #endif #if DBG pIrdaLinkCb->MediaSenseTimer.pName = "MediaSense"; #endif IrdaTimerInitialize(&pIrdaLinkCb->MediaSenseTimer, MediaSenseExp, 0, pIrdaLinkCb, pIrdaLinkCb); NdisAllocateBufferPool(pStatus, &pIrdaLinkCb->BufferPool, IRDA_NDIS_BUFFER_POOL_SIZE); if (*pStatus != NDIS_STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("NdisAllocateBufferPool failed\n"))); goto error10; } NdisAllocatePacketPool(pStatus, &pIrdaLinkCb->PacketPool, IRDA_NDIS_PACKET_POOL_SIZE, sizeof(IRDA_PROTOCOL_RESERVED)-1 + \ sizeof(NDIS_IRDA_PACKET_INFO)); if (*pStatus != NDIS_STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("NdisAllocatePacketPool failed\n"))); goto error20; } NdisInitializeListHead(&pIrdaLinkCb->PacketList); for (i = 0; i < IRDA_NDIS_PACKET_POOL_SIZE; i++) { PIRDA_PROTOCOL_RESERVED pReserved; PNDIS_PACKET NdisPacket; NdisAllocatePacket(pStatus, &NdisPacket, pIrdaLinkCb->PacketPool); if (*pStatus != NDIS_STATUS_SUCCESS) { ASSERT(0); goto error30; } pReserved = (PIRDA_PROTOCOL_RESERVED)(NdisPacket->ProtocolReserved); NdisInterlockedInsertTailList(&pIrdaLinkCb->PacketList, &pReserved->Linkage, &pIrdaLinkCb->SpinLock); } // Allocate a list of Irda messages w/ data for internally // generated LAP messages pIrdaLinkCb->TxMsgFreeListLen = 0; for (i = 0; i < IRDA_MSG_LIST_LEN; i++) { NdisAllocateMemoryWithTag(&pMsg, sizeof(IRDA_MSG) + IRDA_MSG_DATA_SIZE, MT_IRNDIS_TX_IMSG); if (pMsg == NULL) { *pStatus = STATUS_INSUFFICIENT_RESOURCES; goto error40; } NdisInterlockedInsertTailList(&pIrdaLinkCb->TxMsgFreeList, &pMsg->Linkage, &pIrdaLinkCb->SpinLock); pIrdaLinkCb->TxMsgFreeListLen++; } // Build the discovery info Val = HintCharSet; DscvInfoLen = 0; for (i = 0, Mask = 0xFF000000; i < 4; i++, Mask >>= 8) { if (Mask & Val || DscvInfoLen > 0) { DscvInfoBuf[DscvInfoLen++] = (UCHAR) ((Mask & Val) >> (8 * (3-i))); } } BytesToCopy= sizeof(DscvInfoBuf)-DscvInfoLen < NickNameLen ? sizeof(DscvInfoBuf)-DscvInfoLen : NickNameLen; RtlCopyMemory(DscvInfoBuf+DscvInfoLen, NickName, BytesToCopy); DscvInfoLen += BytesToCopy; NdisOpenAdapter( pStatus, &OpenErrorStatus, &pIrdaLinkCb->NdisBindingHandle, &SelectedMediumIndex, MediumArray, 1, NdisIrdaHandle, pIrdaLinkCb, AdapterName, 0, NULL); DEBUGMSG(DBG_NDIS, (TEXT("NdisOpenAdapter(%p), status %x\n"), pIrdaLinkCb->NdisBindingHandle, *pStatus)); if (*pStatus == NDIS_STATUS_PENDING) { NdisWaitEvent(&pIrdaLinkCb->OpenCloseEvent, 0); *pStatus = pIrdaLinkCb->OpenCloseStatus; } if (*pStatus != NDIS_STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: Failed %X\n"), *pStatus)); goto error40; } InitializeLocalQos(&LocalQos, (PNDIS_STRING) SystemSpecific1); // // Query adapters capabilities and store in LocalQos // // // query the adpater for the spuuported speeds // UintArrayCnt = sizeof(UintArray)/sizeof(UINT); *pStatus = IrdaQueryOid(pIrdaLinkCb, OID_IRDA_SUPPORTED_SPEEDS, UintArray, &UintArrayCnt); if (*pStatus != NDIS_STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("Query IRDA_SUPPORTED_SPEEDS failed %x\n"), *pStatus)); goto error50; } OidToLapQos(vBaudTable, UintArray, UintArrayCnt, &LocalQos.bfBaud, FALSE); // // query the adapter for min turn araound time // UintArrayCnt = sizeof(UintArray)/sizeof(UINT); *pStatus = IrdaQueryOid(pIrdaLinkCb, OID_IRDA_TURNAROUND_TIME, UintArray, &UintArrayCnt); if (*pStatus != NDIS_STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("Query IRDA_IRDA_TURNARROUND_TIME failed %x\n"), *pStatus)); goto error50; } OidToLapQos(vMinTATTable, UintArray, UintArrayCnt, &LocalQos.bfMinTurnTime, FALSE); // // query the adapter for max receive window size // UintArrayCnt = sizeof(UintArray)/sizeof(UINT); *pStatus = IrdaQueryOid(pIrdaLinkCb, OID_IRDA_MAX_RECEIVE_WINDOW_SIZE, UintArray, &UintArrayCnt); if (*pStatus != NDIS_STATUS_SUCCESS) { // Not fatal DEBUGMSG(DBG_WARN, (TEXT("Query IRDA_MAX_RECEIVE_WINDOW_SIZE failed %x\n"), *pStatus)); } else { OidToLapQos(vWinSizeTable, UintArray, UintArrayCnt, &LocalQos.bfWindowSize, TRUE); } // // query the adapter for extra bofs // UintArrayCnt = sizeof(UintArray)/sizeof(UINT); *pStatus = IrdaQueryOid(pIrdaLinkCb, OID_IRDA_EXTRA_RCV_BOFS, UintArray, &UintArrayCnt); if (*pStatus != NDIS_STATUS_SUCCESS) { // Not fatal DEBUGMSG(DBG_WARN, (TEXT("Query OID_IRDA_EXTRA_RCV_BOFS failed %x\n"), *pStatus)); } else { OidToLapQos(vBOFSTable, UintArray, UintArrayCnt, &LocalQos.bfBofs, FALSE ); } if (MaxWindow) { LocalQos.bfWindowSize &= MaxWindow; } // Get the window size and data size to determine the number // and size of Irda messages to allocate for receiving frames WinSize = IrlapGetQosParmVal(vWinSizeTable, LocalQos.bfWindowSize, NULL); pIrdaLinkCb->RxMsgDataSize = IrlapGetQosParmVal(vDataSizeTable, LocalQos.bfDataSize, NULL) + IRLAP_HEADER_LEN; pIrdaLinkCb->RxMsgFreeListLen = 0; for (i = 0; i < WinSize + 1; i++) { // Allocate room for data in case we get indicated data // that must be copied (IrdaReceive vs. IrdaReceivePacket) // LATER NOTE: We don't support IrdaReceive now to save locked mem NdisAllocateMemoryWithTag(&pMsg, sizeof(IRDA_MSG) + pIrdaLinkCb->RxMsgDataSize, MT_IRNDIS_RX_IMSG); if (pMsg == NULL) { *pStatus = STATUS_INSUFFICIENT_RESOURCES; goto error50; } NdisInterlockedInsertTailList(&pIrdaLinkCb->RxMsgFreeList, &pMsg->Linkage, &pIrdaLinkCb->SpinLock); pIrdaLinkCb->RxMsgFreeListLen++; } // Create an instance of IrLAP IrlapOpenLink(pStatus, pIrdaLinkCb, &LocalQos, DscvInfoBuf, DscvInfoLen, Slots, NickName, NickNameLen, (UCHAR)(HintCharSet & 0xFF)); if (*pStatus != STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: IrlapOpenLink failed %X\n"), *pStatus)); goto error50; } #ifdef IRDA_RX_SYSTEM_THREAD *pStatus = (NDIS_STATUS) PsCreateSystemThread( &pIrdaLinkCb->hRxThread, (ACCESS_MASK) 0L, NULL, NULL, NULL, RxThread, pIrdaLinkCb); if (*pStatus != STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("IRNDIS: failed create system thread\n"))); goto error60; } #endif goto exit10; error60: LOCK_LINK(pIrdaLinkCb); IrlmpCloseLink(pIrdaLinkCb); UNLOCK_LINK(pIrdaLinkCb); goto exit10; error50: NdisCloseAdapter(&CloseStatus, pIrdaLinkCb->NdisBindingHandle); if (CloseStatus == NDIS_STATUS_PENDING) { NdisWaitEvent(&pIrdaLinkCb->OpenCloseEvent, 0); DEBUGMSG(DBG_NDIS, ("IRNDIS: Close wait complete\n")); } error40: pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->TxMsgFreeList, &pIrdaLinkCb->SpinLock); while (pMsg != NULL) { NdisFreeMemory(pMsg, sizeof(IRDA_MSG) + IRDA_MSG_DATA_SIZE, 0); pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->TxMsgFreeList, &pIrdaLinkCb->SpinLock); } pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->RxMsgFreeList, &pIrdaLinkCb->SpinLock); while (pMsg != NULL) { NdisFreeMemory(pMsg, sizeof(IRDA_MSG), 0); pMsg = (IRDA_MSG *) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->RxMsgFreeList, &pIrdaLinkCb->SpinLock); } error30: for (i = 0; i < IRDA_NDIS_PACKET_POOL_SIZE; i++) { PIRDA_PROTOCOL_RESERVED pReserved; PNDIS_PACKET NdisPacket; pReserved = (PIRDA_PROTOCOL_RESERVED) NdisInterlockedRemoveHeadList( &pIrdaLinkCb->PacketList, &pIrdaLinkCb->SpinLock); if (pReserved == NULL) { DEBUGMSG(DBG_ERROR, (TEXT("Not all NdisPackets were on list when deleting\n"))); ASSERT(0); break;; } NdisPacket = CONTAINING_RECORD(pReserved, NDIS_PACKET, ProtocolReserved); NdisFreePacket(NdisPacket); } NdisFreePacketPool(pIrdaLinkCb->PacketPool); error20: NdisFreeBufferPool(pIrdaLinkCb->BufferPool); error10: NdisFreeMemory(pIrdaLinkCb, sizeof(IRDA_LINK_CB), 0); exit10: DEBUGMSG(DBG_NDIS, (TEXT("IRNDIS: -IrdaBindAdapter() status %x\n"), *pStatus)); return; } /*************************************************************************** * * Protocol unbind adapter handler * */ VOID IrdaUnbindAdapter( OUT PNDIS_STATUS pStatus, IN NDIS_HANDLE IrdaBindingContext, IN NDIS_HANDLE UnbindContext ) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext; DEBUGMSG(DBG_IRMAC, (TEXT("+IrdaUnbindAdapter()\n"))); pIrdaLinkCb->UnbindContext = UnbindContext; #ifdef IRDA_RX_SYSTEM_THREAD KeSetEvent(&pIrdaLinkCb->EvKillRxThread, 0, FALSE); #endif LOCK_LINK(pIrdaLinkCb); IrlmpCloseLink(pIrdaLinkCb); UNLOCK_LINK(pIrdaLinkCb); *pStatus = NDIS_STATUS_PENDING; DEBUGMSG(DBG_IRMAC, (TEXT("-IrdaUnbindAdapter() Status %x\n"), *pStatus)); return; } NDIS_STATUS IrdaPnpEvent( IN NDIS_HANDLE IrdaBindingContext, IN PNET_PNP_EVENT pNetPnpEvent ) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaBindingContext; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; DEBUGMSG(DBG_IRMAC, (TEXT("IRNDIS: PnpEvent:%p, NetEvent:%d Buffer:%p(%d)\n"), pNetPnpEvent, pNetPnpEvent->NetEvent, pNetPnpEvent->Buffer, pNetPnpEvent->BufferLength)); switch (pNetPnpEvent->NetEvent) { case NetEventQueryPower: break; case NetEventSetPower: { PNET_DEVICE_POWER_STATE pPowerState = pNetPnpEvent->Buffer; ASSERT(pPowerState); if (*pPowerState == NetDeviceStateD0) { DEBUGMSG(DBG_IRMAC, (TEXT("IRNDIS: NetEventSetPower, full power state\n"))); pIrdaLinkCb->LowPowerSt = FALSE; } else { NDIS_STATUS ResetStatus; DEBUGMSG(DBG_IRMAC, (TEXT("IRNDIS: NetEventSetPower, low power state\n"))); pIrdaLinkCb->LowPowerSt = TRUE; if (pIrdaLinkCb->SendOutCnt > 0) { NdisResetEvent(&pIrdaLinkCb->ResetEvent); NdisReset( &ResetStatus, pIrdaLinkCb->NdisBindingHandle ); if (ResetStatus == NDIS_STATUS_PENDING) { NdisWaitEvent(&pIrdaLinkCb->ResetEvent,0); } } NdisAcquireSpinLock(&pIrdaLinkCb->SpinLock); if (pIrdaLinkCb->SendOutCnt) { pIrdaLinkCb->pNetPnpEvent = pNetPnpEvent; Status = NDIS_STATUS_PENDING; } NdisReleaseSpinLock(&pIrdaLinkCb->SpinLock); } } } return Status; } /*************************************************************************** * * IrdaInitialize - register Irda with Ndis, get Irlap parms from registry * */ NTSTATUS IrdaInitialize( PNDIS_STRING ProtocolName, PUNICODE_STRING RegistryPath, PUINT pLazyDscvInterval) { NDIS_STATUS Status; NDIS_PROTOCOL_CHARACTERISTICS pc; OBJECT_ATTRIBUTES ObjectAttribs; HANDLE KeyHandle; UNICODE_STRING ValStr; PKEY_VALUE_FULL_INFORMATION FullInfo; ULONG Result; UCHAR Buf[WORK_BUF_SIZE]; WCHAR StrBuf[WORK_BUF_SIZE]; UNICODE_STRING Path; ULONG i, Multiplier; ULONG PagingFlags = 0; DEBUGMSG(DBG_NDIS,(TEXT("+IrdaInitialize()\n"))); // Get protocol configuration from registry Path.Buffer = StrBuf; Path.MaximumLength = WORK_BUF_SIZE; Path.Length = 0; RtlAppendUnicodeStringToString(&Path, RegistryPath); RtlAppendUnicodeToString(&Path, L"\\Parameters"); InitializeObjectAttributes(&ObjectAttribs, &Path, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttribs); Slots = IRLAP_DEFAULT_SLOTS; HintCharSet = IRLAP_DEFAULT_HINTCHARSET; DisconnectTime = IRLAP_DEFAULT_DISCONNECTTIME; *pLazyDscvInterval = 0; if (Status == STATUS_SUCCESS) { RtlInitUnicodeString(&ValStr, L"PagingFlags"); FullInfo = (PKEY_VALUE_FULL_INFORMATION) Buf; Status = ZwQueryValueKey(KeyHandle, &ValStr, KeyValueFullInformation, FullInfo, WORK_BUF_SIZE, &Result); if (Status == STATUS_SUCCESS && FullInfo->Type == REG_DWORD) { PagingFlags = *((ULONG UNALIGNED *) ((PCHAR)FullInfo + FullInfo->DataOffset)); DEBUGMSG(DBG_IRMAC, (TEXT("IRDA: Registry PagingFlags %X\n"), PagingFlags)); } RtlInitUnicodeString(&ValStr, L"DiscoveryRate"); FullInfo = (PKEY_VALUE_FULL_INFORMATION) Buf; Status = ZwQueryValueKey(KeyHandle, &ValStr, KeyValueFullInformation, FullInfo, WORK_BUF_SIZE, &Result); if (Status == STATUS_SUCCESS && FullInfo->Type == REG_DWORD) { *pLazyDscvInterval = *((ULONG UNALIGNED *) ((PCHAR)FullInfo + FullInfo->DataOffset)); DEBUGMSG(DBG_IRMAC, (TEXT("IRDA: Registry LasyDscvInterval %d\n"), *pLazyDscvInterval)); } RtlInitUnicodeString(&ValStr, L"Slots"); FullInfo = (PKEY_VALUE_FULL_INFORMATION) Buf; Status = ZwQueryValueKey(KeyHandle, &ValStr, KeyValueFullInformation, FullInfo, WORK_BUF_SIZE, &Result); if (Status == STATUS_SUCCESS && FullInfo->Type == REG_DWORD) { Slots = *((ULONG UNALIGNED *) ((PCHAR)FullInfo + FullInfo->DataOffset)); DEBUGMSG(DBG_IRMAC, (TEXT("IRDA: Registry slots %d\n"), Slots)); } RtlInitUnicodeString(&ValStr, L"HINTCHARSET"); FullInfo = (PKEY_VALUE_FULL_INFORMATION) Buf; Status = ZwQueryValueKey(KeyHandle, &ValStr, KeyValueFullInformation, FullInfo, WORK_BUF_SIZE, &Result); if (Status == STATUS_SUCCESS && FullInfo->Type == REG_DWORD) { HintCharSet = *((ULONG UNALIGNED *) ((PCHAR)FullInfo + FullInfo->DataOffset)); DEBUGMSG(DBG_IRMAC, (TEXT("IRDA: Registry HintCharSet %X\n"), HintCharSet)); } RtlInitUnicodeString(&ValStr, L"DISCONNECTTIME"); FullInfo = (PKEY_VALUE_FULL_INFORMATION) Buf; Status = ZwQueryValueKey(KeyHandle, &ValStr, KeyValueFullInformation, FullInfo, WORK_BUF_SIZE, &Result); if (Status == STATUS_SUCCESS && FullInfo->Type == REG_DWORD) { DisconnectTime = *((ULONG UNALIGNED *) ((PCHAR)FullInfo + FullInfo->DataOffset)); DEBUGMSG(DBG_IRMAC, (TEXT("IRDA: Registry DisconnectTime %X\n"), DisconnectTime)); } RtlInitUnicodeString(&ValStr, L"WindowSize"); FullInfo = (PKEY_VALUE_FULL_INFORMATION) Buf; Status = ZwQueryValueKey(KeyHandle, &ValStr, KeyValueFullInformation, FullInfo, WORK_BUF_SIZE, &Result); if (Status == STATUS_SUCCESS && FullInfo->Type == REG_DWORD) { MaxWindow = *((ULONG UNALIGNED *) ((PCHAR)FullInfo + FullInfo->DataOffset)); DEBUGMSG(DBG_IRMAC, (TEXT("IRDA: Registry MaxWindow %X\n"), MaxWindow)); } ZwClose(KeyHandle); } else DEBUGMSG(DBG_IRMAC, (TEXT("Failed to open key %x\n"), Status)); DEBUGMSG(DBG_NDIS, (TEXT("Slots %x, HintCharSet %x, Disconnect %x\n"), Slots, HintCharSet, DisconnectTime)); // // adjust the Slots value to make sure it is valid. Can only be 1, 6, 8, 16 // if (Slots > 8) { Slots = 16; } else { if (Slots > 6) { Slots = 8; } else { if (Slots > 1) { Slots = 6; } else { Slots = 1; } } } // // Use the ComputerName as the discovery nickname // RtlZeroMemory(&NickName,sizeof(NickName)); NickNameLen = 0; RtlInitUnicodeString( &Path, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"); InitializeObjectAttributes(&ObjectAttribs, &Path, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttribs); if (Status == STATUS_SUCCESS) { RtlInitUnicodeString(&ValStr, L"ComputerName"); FullInfo = (PKEY_VALUE_FULL_INFORMATION) Buf; Status = ZwQueryValueKey(KeyHandle, &ValStr, KeyValueFullInformation, FullInfo, WORK_BUF_SIZE, &Result); NickNameLen = 0; HintCharSet &= ~0xff; // // check to see if any of the machine name characters are non ansi, if so // use unicode. Otherwise, send as ansi so more characters can be displayed. // for (i=0; i< FullInfo->DataLength/sizeof(WCHAR); i++) { PWCHAR SourceString=(PWCHAR)((PUCHAR)FullInfo + FullInfo->DataOffset); if (SourceString[i] > 127) { HintCharSet |= UNICODE_CHAR_SET; break; } } if ((HintCharSet & 0XFF) == UNICODE_CHAR_SET) { PWCHAR SourceString=(PWCHAR)((PUCHAR)FullInfo + FullInfo->DataOffset); PWCHAR DestString=(PWCHAR)NickName; for (i=0; i< FullInfo->DataLength/sizeof(WCHAR) && i < NICK_NAME_LEN/sizeof(WCHAR) ; i++) { DestString[i]=SourceString[i]; NickNameLen+=sizeof(WCHAR); } } else { UNICODE_STRING SourceString; ANSI_STRING DestString; SourceString.Length=(USHORT)FullInfo->DataLength; SourceString.MaximumLength=SourceString.Length; SourceString.Buffer=(PWCHAR)((PUCHAR)FullInfo + FullInfo->DataOffset); DestString.MaximumLength=NICK_NAME_LEN; DestString.Buffer=NickName; RtlUnicodeStringToAnsiString(&DestString, &SourceString, FALSE); NickNameLen=DestString.Length; } ZwClose(KeyHandle); } // Disable paging of code and data if indicated in registery if (PagingFlags & DISABLE_CODE_PAGING) { // Any function in the section PAGEIRDA that is locked down // will cause the entire section to be locked into memory MmLockPagableCodeSection(OidToLapQos); DEBUGMSG(DBG_WARN, (TEXT("IRNDIS: Code paging is disabled\n"))); } if (PagingFlags & DISABLE_DATA_PAGING) { MmLockPagableDataSection(&DisconnectTime); DEBUGMSG(DBG_WARN, (TEXT("IRNDIS: Data paging is disabled\n"))); } // Register protocol with Ndis NdisZeroMemory((PVOID)&pc, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); pc.MajorNdisVersion = 0x04; pc.MinorNdisVersion = 0x00; pc.OpenAdapterCompleteHandler = IrdaOpenAdapterComplete; pc.CloseAdapterCompleteHandler = IrdaCloseAdapterComplete; pc.SendCompleteHandler = IrdaSendComplete; pc.TransferDataCompleteHandler = IrdaTransferDataComplete; pc.ResetCompleteHandler = IrdaResetComplete; pc.RequestCompleteHandler = IrdaRequestComplete; pc.ReceiveHandler = IrdaReceive; pc.ReceiveCompleteHandler = IrdaReceiveComplete; pc.StatusHandler = IrdaStatus; pc.StatusCompleteHandler = IrdaStatusComplete; pc.BindAdapterHandler = IrdaBindAdapter; pc.UnbindAdapterHandler = IrdaUnbindAdapter; pc.UnloadHandler = NULL; pc.Name = *ProtocolName; pc.ReceivePacketHandler = IrdaReceivePacket; #if defined(_PNP_POWER_) pc.PnPEventHandler = IrdaPnpEvent; #endif NdisRegisterProtocol(&Status, &NdisIrdaHandle, (PNDIS_PROTOCOL_CHARACTERISTICS)&pc, sizeof(NDIS40_PROTOCOL_CHARACTERISTICS)); IrlmpInitialize(); DEBUGMSG(DBG_NDIS, (TEXT("-IrdaInitialize(), rc %x\n"), Status)); return Status; }