You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2288 lines
70 KiB
2288 lines
70 KiB
/*****************************************************************************
|
|
*
|
|
* 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 <irda.h>
|
|
#include <ntddndis.h>
|
|
#include <ndis.h>
|
|
#include <irioctl.h>
|
|
#include <irlap.h>
|
|
#include <irlapp.h>
|
|
#include <irlmp.h>
|
|
#include <irmem.h>
|
|
#include <decdirda.h>
|
|
#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<<j;
|
|
if (MaxVal)
|
|
return;
|
|
}
|
|
else if (MaxVal)
|
|
{
|
|
*pBitField |= 1<<j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* Perform a synchronous request for an OID
|
|
*
|
|
*/
|
|
NDIS_STATUS
|
|
IrdaQueryOid(
|
|
IN PIRDA_LINK_CB pIrdaLinkCb,
|
|
IN NDIS_OID Oid,
|
|
OUT PUINT pQBuf,
|
|
IN OUT PUINT pQBufLen)
|
|
{
|
|
IRDA_REQUEST Request;
|
|
|
|
NDIS_STATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
NdisInitializeEvent(&Request.Event);
|
|
NdisResetEvent(&Request.Event);
|
|
|
|
Request.NdisRequest.RequestType = NdisRequestQueryInformation;
|
|
Request.NdisRequest.DATA.QUERY_INFORMATION.Oid = Oid;
|
|
Request.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = pQBuf;
|
|
Request.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = *pQBufLen * sizeof(UINT);
|
|
|
|
|
|
NdisRequest(&Status, pIrdaLinkCb->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;
|
|
}
|