📄 irlmp.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*****************************************************************************
*
*
* @doc
* @module irlmp.c | Provides IrLMP API
*
* Date: 4/15/95
*
* @comm
*
* This module exports the following API's:
*
* IrlmpOpenLink()
* IrlmpCloseLink()
* IrlmpDown()
* IrlmpUp()
*
*
* |---------|
* | Tdi |
* |---------|
* /|\ |
* | |
* TdiUp() | | IrlmpDown()
* | |
* | \|/
* |---------| IrdaTimerStart() |-------|
* | |-------------------------->| |
* | IRLMP | | TIMER |
* | |<--------------------------| |
* |---------| ExpFunc() |-------|
* /|\ |
* | |
* IrlmpUp() | | IrlapDown()
* | |
* | \|/
* |---------|
* | IRLAP |
* |---------|
*
* See irda.h for complete message definitions
*
* Connection context for IRLMP and Tdi are exchanged
* during connection establishment:
*
* Active connection:
* +------------+ IRLMP_CONNECT_REQ(TdiContext) +-------+
* | |---------------------------------------->| |
* | Tdi | IRLMP_CONNECT_CONF(IrlmpContext) | IRMLP |
* | |<----------------------------------------| |
* +------------+ +-------+
*
* Passive connection:
* +------------+ IRLMP_CONNECT_IND(IrlmpContext) +-------+
* | |<----------------------------------------| |
* | Tdi | IRLMP_CONNECT_RESP(TdiContext) | IRMLP |
* | |---------------------------------------->| |
* +------------+ +-------+
*
*
* Tdi calling IrlmpDown(void *pIrlmpContext, IRDA_MSG *pMsg)
* pIrlmpContext = NULL for the following:
* pMsg->Prim = IRLMP_DISCOVERY_REQ,
* IRLMP_CONNECT_REQ,
* IRLMP_FLOWON_REQ,
* IRLMP_GETVALUEBYCLASS_REQ.
* In all other cases, the pIRLMPContext must be a valid context.
*
* IRLMP calling TdiUp(void *pTdiContext, IRDA_MSG *pMsg)
* pTdiContext = NULL for the following:
* pMsg->Prim = IRLAP_STATUS_IND,
* IRLMP_DISCOVERY_CONF,
* IRLMP_CONNECT_IND,
* IRLMP_GETVALUEBYCLASS_CONF.
* In all other cases, the pTdiContext will have a valid context.
*/
#include <irda.h>
#include <irlap.h>
#include <irlmp.h>
#include <irlmpp.h>
// IAS
UCHAR IAS_IrLMPSupport[] = {IAS_IRLMP_VERSION, IAS_SUPPORT_BIT_FIELD,
IAS_LMMUX_SUPPORT_BIT_FIELD};
const CHAR IasClassName_Device[] = "Device";
const CHAR IasAttribName_DeviceName[] = "DeviceName";
const CHAR IasAttribName_IrLMPSupport[] = "IrLMPSupport";
const CHAR IasAttribName_TTPLsapSel[] = "IrDA:TinyTP:LsapSel";
const CHAR IasAttribName_IrLMPLsapSel[] = "IrDA:IrLMP:LsapSel";
const CHAR IasAttribName_IrLMPLsapSel2[] = "IrDA:IrLMP:LSAPSel"; // jeez
const UCHAR IasClassNameLen_Device = sizeof(IasClassName_Device)-1;
const UCHAR IasAttribNameLen_DeviceName = sizeof(IasAttribName_DeviceName)-1;
const UCHAR IasAttribNameLen_IrLMPSupport = sizeof(IasAttribName_IrLMPSupport)-1;
const UCHAR IasAttribNameLen_TTPLsapSel = sizeof(IasAttribName_TTPLsapSel)-1;
const UCHAR IasAttribNameLen_IrLMPLsapSel = sizeof(IasAttribName_IrLMPLsapSel)-1;
// Globals
LIST_ENTRY RegisteredLsaps;
LIST_ENTRY DeviceList;
LIST_ENTRY IasObjects;
IRDA_EVENT EvDiscoveryReq;
IRDA_EVENT EvConnectReq;
IRDA_EVENT EvConnectResp;
IRDA_EVENT EvLmConnectReq;
IRDA_EVENT EvIrlmpCloseLink;
BOOLEAN DscvReqScheduled;
LIST_ENTRY IrdaLinkCbList;
NDIS_SPIN_LOCK SpinLock;
// Prototypes
STATIC UINT CreateLsap(PIRLMP_LINK_CB, IRLMP_LSAP_CB **);
STATIC VOID DeleteLsap(IRLMP_LSAP_CB *);
STATIC VOID CleanupLsap(IRLMP_LSAP_CB *pLsapCb);
STATIC VOID TearDownConnections(PIRLMP_LINK_CB, IRLMP_DISC_REASON);
STATIC VOID IrlmpMoreCreditReq(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC VOID IrlmpDiscoveryReq(IRDA_MSG *pMsg);
STATIC UINT IrlmpLinkControlReq(IRDA_MSG *);
STATIC UINT IrlmpConnectReq(IRDA_MSG *);
STATIC UINT IrlmpConnectResp(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC UINT IrlmpDisconnectReq(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC UINT IrlmpDataReqExclusive(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC UINT IrlmpDataReqMultiplexed(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC VOID FormatAndSendDataReq(IRLMP_LSAP_CB *, IRDA_MSG *, BOOLEAN);
STATIC UINT IrlmpAccessModeReq(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC void SetupTtp(IRLMP_LSAP_CB *);
STATIC VOID SendCntlPdu(IRLMP_LSAP_CB *, int, int, int, int);
STATIC VOID LsapResponseTimerExp(PVOID);
STATIC VOID IrlapDiscoveryConf(PIRLMP_LINK_CB, IRDA_MSG *);
STATIC void UpdateDeviceList(PIRDA_LINK_CB, LIST_ENTRY *);
STATIC VOID IrlapConnectInd(PIRLMP_LINK_CB, IRDA_MSG *pMsg);
STATIC VOID IrlapConnectConf(PIRLMP_LINK_CB, IRDA_MSG *pMsg);
STATIC VOID IrlapDisconnectInd(PIRLMP_LINK_CB, IRDA_MSG *pMsg);
STATIC IRLMP_LSAP_CB *GetLsapInState(PIRLMP_LINK_CB, int, int, BOOLEAN);
STATIC IRLMP_LINK_CB *GetIrlmpCb(PUCHAR);
STATIC VOID DiscDelayTimerFunc(PVOID);
STATIC VOID IrlapDataConf(IRDA_MSG *pMsg);
STATIC VOID IrlapDataInd(PIRLMP_LINK_CB, IRDA_MSG *pMsg);
STATIC VOID LmPduConnectReq(PIRLMP_LINK_CB, IRDA_MSG *, int, int, UCHAR *);
STATIC VOID LmPduConnectConf(PIRLMP_LINK_CB, IRDA_MSG *, int, int, UCHAR *);
STATIC VOID LmPduDisconnectReq(PIRLMP_LINK_CB, IRDA_MSG *, int, int, UCHAR *);
STATIC VOID SendCreditPdu(IRLMP_LSAP_CB *);
STATIC VOID LmPduData(PIRLMP_LINK_CB, IRDA_MSG *, int, int);
STATIC VOID SetupTtpAndStoreConnData(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC VOID LmPduAccessModeReq(PIRLMP_LINK_CB, int, int, UCHAR *, UCHAR *);
STATIC VOID LmPduAccessModeConf(PIRLMP_LINK_CB, int, int, UCHAR *, UCHAR *);
STATIC IRLMP_LSAP_CB *GetLsap(PIRLMP_LINK_CB, int, int);
STATIC VOID UnroutableSendLMDisc(PIRLMP_LINK_CB, int, int);
STATIC VOID ScheduleConnectReq(PIRLMP_LINK_CB);
STATIC void InitiateCloseLink(PVOID Context);
STATIC void InitiateConnectReq(PVOID Context);
STATIC void InitiateDiscoveryReq(PVOID Context);
STATIC void InitiateConnectResp(PVOID Context);
STATIC void InitiateLMConnectReq(PVOID Context);
STATIC UINT IrlmpGetValueByClassReq(IRDA_MSG *);
STATIC IAS_OBJECT *IasGetObject(CHAR *pClassName);
STATIC IasGetValueByClass(const CHAR *, int, const CHAR *, int, void **,
int *, UCHAR *);
STATIC VOID IasConnectReq(PIRLMP_LINK_CB, int);
STATIC VOID IasServerDisconnectReq(IRLMP_LSAP_CB *pLsapCb);
STATIC VOID IasClientDisconnectReq(IRLMP_LSAP_CB *pLsapCb, IRLMP_DISC_REASON);
STATIC VOID IasSendQueryResp(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC VOID IasProcessQueryResp(PIRLMP_LINK_CB, IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC VOID SendGetValueByClassReq(IRLMP_LSAP_CB *);
STATIC VOID SendGetValueByClassResp(IRLMP_LSAP_CB *, IRDA_MSG *);
STATIC VOID RegisterLsapProtocol(int Lsap, BOOLEAN UseTTP);
STATIC UINT IasAddAttribute(IAS_SET *pIASSet, PVOID *pAttribHandle);
STATIC VOID IasDelAttribute(PVOID AttribHandle);
STATIC VOID UpdateIasDeviceName(PIRLMP_LINK_CB pIrlmpCb);
/*****************************************************************************
*
*/
VOID
IrlmpInitialize()
{
InitializeListHead(&RegisteredLsaps);
InitializeListHead(&DeviceList);
InitializeListHead(&IasObjects);
InitializeListHead(&IrdaLinkCbList);
NdisAllocateSpinLock(&SpinLock);
DscvReqScheduled = FALSE;
IrdaEventInitialize(&EvDiscoveryReq, InitiateDiscoveryReq);
IrdaEventInitialize(&EvConnectReq, InitiateConnectReq);
IrdaEventInitialize(&EvConnectResp,InitiateConnectResp);
IrdaEventInitialize(&EvLmConnectReq, InitiateLMConnectReq);
IrdaEventInitialize(&EvIrlmpCloseLink, InitiateCloseLink);
}
/*****************************************************************************
*
*/
VOID
IrdaShutdown()
{
PIRDA_LINK_CB pIrdaLinkCb, pIrdaLinkCbNext;
#ifndef UNDER_CE
LARGE_INTEGER SleepMs;
#endif
NTSTATUS Status;
UINT Seconds;
// This needs to be fixed
#ifndef UNDER_CE
SleepMs.QuadPart = -(10*1000*1000); // 1 second
#endif
NdisAcquireSpinLock(&SpinLock);
for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
(LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
pIrdaLinkCb = pIrdaLinkCbNext)
{
pIrdaLinkCbNext = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink;
NdisReleaseSpinLock(&SpinLock);
IrlmpCloseLink(pIrdaLinkCb);
NdisAcquireSpinLock(&SpinLock);
}
NdisReleaseSpinLock(&SpinLock);
Seconds = 0;
while (Seconds < 30)
{
if (IsListEmpty(&IrdaLinkCbList))
break;
#ifdef UNDER_CE
Sleep(1000);
#else
KeDelayExecutionThread(KernelMode, FALSE, &SleepMs);
#endif
Seconds++;
}
#ifdef UNDER_CE
Sleep(1000);
ASSERT(Seconds < 30);
#else
#if DBG
if (Seconds >= 30)
{
DbgPrint("Link left open at shutdown!\n");
for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
(LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
pIrdaLinkCb = pIrdaLinkCbNext)
{
DbgPrint("pIrdaLinkCb: %X\n", pIrdaLinkCb);
DbgPrint(" pIrlmpCb: %X\n", pIrdaLinkCb->IrlmpContext);
DbgPrint(" pIrlapCb: %X\n", pIrdaLinkCb->IrlapContext);
}
ASSERT(0);
}
else
{
DbgPrint("Irda shutdown complete\n");
}
#endif
KeDelayExecutionThread(KernelMode, FALSE, &SleepMs);
#endif
NdisFreeSpinLock(&SpinLock);
NdisDeregisterProtocol(&Status, NdisIrdaHandle);
}
/*****************************************************************************
*
*/
VOID
IrlmpOpenLink(OUT PNTSTATUS Status,
IN PIRDA_LINK_CB pIrdaLinkCb,
IN UCHAR *pDeviceName,
IN int DeviceNameLen,
IN UCHAR CharSet)
{
PIRLMP_LINK_CB pIrlmpCb;
UINT rc;
IAS_SET *pIASSet;
*Status = STATUS_SUCCESS;
if ((pIrlmpCb = CTEAllocMem(sizeof(IRLMP_LINK_CB))) == NULL)
{
DEBUGMSG(DBG_ERROR, (TEXT("Alloc failed\n")));
*Status = STATUS_INSUFFICIENT_RESOURCES;
return;
}
pIASSet = (IAS_SET *)IrdaAlloc(sizeof(IAS_SET) + 128, 0);
if (NULL == pIASSet) {
CTEFreeMem(pIrlmpCb);
DEBUGMSG(DBG_ERROR, (TEXT("IAS_SET Alloc failed\n")));
*Status = STATUS_INSUFFICIENT_RESOURCES;
return;
}
pIrdaLinkCb->IrlmpContext = pIrlmpCb;
#if DBG
pIrlmpCb->DiscDelayTimer.pName = "DiscDelay";
#endif
IrdaTimerInitialize(&pIrlmpCb->DiscDelayTimer,
DiscDelayTimerFunc,
IRLMP_DISCONNECT_DELAY_TIMEOUT,
pIrlmpCb,
pIrdaLinkCb);
InitializeListHead(&pIrlmpCb->LsapCbList);
pIrlmpCb->pIrdaLinkCb = pIrdaLinkCb;
pIrlmpCb->ConnReqScheduled = FALSE;
pIrlmpCb->LinkState = LINK_DISCONNECTED;
pIrlmpCb->pExclLsapCb = NULL;
pIrlmpCb->pIasQuery = NULL;
// ConnDevAddrSet is set to true if LINK_IN_DISCOVERY or
// LINK_DISCONNECTING and an LSAP requests a connection. Subsequent
// LSAP connection requests check to see if this flag is set. If so
// the requested device address must match that contained in the
// IRLMP control block (set by the first connect request)
pIrlmpCb->ConnDevAddrSet = FALSE;
// Add device info to IAS
RtlCopyMemory(pIASSet->irdaClassName, IasClassName_Device,
IasClassNameLen_Device+1);
RtlCopyMemory(pIASSet->irdaAttribName, IasAttribName_DeviceName,
IasAttribNameLen_DeviceName+1);
pIASSet->irdaAttribType = IAS_ATTRIB_VAL_STRING;
DeviceNameLen = min(DeviceNameLen, sizeof(pIASSet->irdaAttribute.irdaAttribUsrStr.UsrStr));
RtlCopyMemory(pIASSet->irdaAttribute.irdaAttribUsrStr.UsrStr,
pDeviceName,
DeviceNameLen + 1);
pIASSet->irdaAttribute.irdaAttribUsrStr.CharSet = CharSet;
pIASSet->irdaAttribute.irdaAttribUsrStr.Len = DeviceNameLen;
rc = IasAddAttribute(pIASSet, &pIrlmpCb->hAttribDeviceName);
ASSERT(rc == 0);
RtlCopyMemory(pIASSet->irdaClassName, IasClassName_Device,
IasClassNameLen_Device+1);
RtlCopyMemory(pIASSet->irdaAttribName, IasAttribName_IrLMPSupport,
IasAttribNameLen_IrLMPSupport+1);
pIASSet->irdaAttribType = IAS_ATTRIB_VAL_BINARY;
RtlCopyMemory(pIASSet->irdaAttribute.irdaAttribOctetSeq.OctetSeq,
IAS_IrLMPSupport, sizeof(IAS_IrLMPSupport));
pIASSet->irdaAttribute.irdaAttribOctetSeq.Len =
sizeof(IAS_IrLMPSupport);
rc = IasAddAttribute(pIASSet, &pIrlmpCb->hAttribIrlmpSupport);
ASSERT(rc == 0);
if (*Status != STATUS_SUCCESS)
{
CTEFreeMem(pIrlmpCb);
}
else
{
NdisInterlockedInsertTailList(&IrdaLinkCbList,
&pIrdaLinkCb->Linkage,
&SpinLock);
}
IrdaFree(pIASSet);
DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP initialized, status %x\n"), *Status));
return;
}
/*****************************************************************************
*
*
*
*/
VOID
IrlmpDeleteInstance(PVOID Context)
{
PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) Context;
PVOID LinkContext = pIrlmpCb->pIrdaLinkCb;
IRDA_DEVICE *pDevice, *pNextDevice;
NdisAcquireSpinLock(&SpinLock);
for (pDevice = (IRDA_DEVICE *) DeviceList.Flink;
(LIST_ENTRY *) pDevice != &DeviceList;
pDevice = pNextDevice)
{
pNextDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink;
if (LinkContext == pDevice->LinkContext)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -