📄 irlmp.c
字号:
case IRLMP_CONNECT_RESP:
rc = IrlmpConnectResp(pLsapCb, pMsg);
break;
case IRLMP_DISCONNECT_REQ:
rc = IrlmpDisconnectReq(pLsapCb, pMsg);
break;
case IRLMP_DATA_REQ:
if (pLsapCb->pIrlmpCb->pExclLsapCb != NULL)
{
rc = IrlmpDataReqExclusive(pLsapCb, pMsg);
}
else
{
rc = IrlmpDataReqMultiplexed(pLsapCb, pMsg);
}
break;
case IRLMP_ACCESSMODE_REQ:
rc = IrlmpAccessModeReq(pLsapCb, pMsg);
break;
case IRLMP_MORECREDIT_REQ:
IrlmpMoreCreditReq(pLsapCb, pMsg);
break;
case IRLMP_GETVALUEBYCLASS_REQ:
rc = IrlmpGetValueByClassReq(pMsg);
break;
case IRLMP_REGISTERLSAP_REQ:
RegisterLsapProtocol(pMsg->IRDA_MSG_LocalLsapSel,
pMsg->IRDA_MSG_UseTtp);
break;
case IRLMP_DEREGISTERLSAP_REQ:
DeregisterLsapProtocol(pMsg->IRDA_MSG_LocalLsapSel);
break;
case IRLMP_ADDATTRIBUTE_REQ:
rc = IasAddAttribute(pMsg->IRDA_MSG_pIasSet, pMsg->IRDA_MSG_pAttribHandle);
break;
case IRLMP_DELATTRIBUTE_REQ:
IasDelAttribute(pMsg->IRDA_MSG_AttribHandle);
break;
case IRLMP_LINKCONTROL_REQ:
rc = IrlmpLinkControlReq(pMsg);
break;
default:
ASSERT(0);
}
if (pLsapCb)
{
UNLOCK_LINK(pLsapCb->pIrlmpCb->pIrdaLinkCb);
REFDEL(&pLsapCb->RefCnt, 'NWOD');
}
return rc;
}
UINT
IrlmpLinkControlReq(IRDA_MSG *pMsg)
{
PIRDA_LINK_CB pIrdaLinkCb, pIrdaLinkCbNext;
UINT rc = SUCCESS;
PIRLMP_LINK_CB pIrlmpCb;
NdisAcquireSpinLock(&SpinLock);
for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
(LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
pIrdaLinkCb = pIrdaLinkCbNext)
{
pIrdaLinkCbNext = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink;
pIrlmpCb = pIrdaLinkCb->IrlmpContext;
while (pIrlmpCb->LinkState != LINK_DISCONNECTED)
{
NdisReleaseSpinLock(&SpinLock);
// TDI should ensure that we never get a connect request while
// we are trying to release the link.
DEBUGMSG(ZONE_WARN,
(TEXT("Irlmp: waiting for LMP to disconnect to release link.\r\n"))
);
Sleep(500);
NdisAcquireSpinLock(&SpinLock);
}
NdisReleaseSpinLock(&SpinLock);
// If we are re-acquiring resources, we need to reload the device
// name and change the IAS database.
if (pMsg->IRDA_MSG_AcquireResources == TRUE)
{
UpdateIasDeviceName(pIrlmpCb);
}
pMsg->Prim = IRLAP_LINKCONTROL_REQ;
// AcquireResources is already set.
// Currently we will not use the link configuration block.
pMsg->IRDA_MSG_pLinkConfig = NULL;
pMsg->IRDA_MSG_pLinkContext = pIrdaLinkCb;
rc = IrlapDown(pIrdaLinkCb->IrlapContext, pMsg);
NdisAcquireSpinLock(&SpinLock);
if (rc != SUCCESS)
{
DEBUGMSG(DBG_ERROR,
(TEXT("IRLAP_LINKCONTROL_REQ failure - 0x%x\r\n"), rc));
break;
}
}
NdisReleaseSpinLock(&SpinLock);
return (rc);
}
VOID
IrlmpMoreCreditReq(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
{
int CurrentAvail = pLsapCb->AvailableCredit;
pLsapCb->AvailableCredit += pMsg->IRDA_MSG_TtpCredits;
if (pLsapCb->UseTtp)
{
if ((CurrentAvail == 0) || (pLsapCb->RemoteTxCredit == 0))
{
// remote peer completely out of credit, send'm some
SendCreditPdu(pLsapCb);
}
}
else
{
if (pLsapCb == pLsapCb->pIrlmpCb->pExclLsapCb)
{
pLsapCb->RemoteTxCredit += pMsg->IRDA_MSG_TtpCredits;
pMsg->Prim = IRLAP_FLOWON_REQ;
IrlapDown(pLsapCb->pIrlmpCb->pIrdaLinkCb->IrlapContext, pMsg);
}
}
}
/*****************************************************************************
*
* @func UINT | IrlmpDiscoveryReq | initiates a discovery request
*
* @rdesc SUCCESS or an error code
*
* @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
*/
VOID
IrlmpDiscoveryReq(IRDA_MSG *pMsg)
{
PIRDA_LINK_CB pIrdaLinkCb;
PIRLMP_LINK_CB pIrlmpCb;
DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: IRLMP_DISCOVERY_REQ\n")));
NdisAcquireSpinLock(&SpinLock);
if (DscvReqScheduled)
{
DEBUGMSG(DBG_IRLMP, (TEXT("Discovery already schedule\n")));
NdisReleaseSpinLock(&SpinLock);
}
else
{
// Flag each link for discovery
for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
(LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
pIrdaLinkCb = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink)
{
pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
pIrlmpCb->DiscoveryPending = TRUE;
}
DscvReqScheduled = TRUE;
NdisReleaseSpinLock(&SpinLock);
// Schedule the first link
IrdaEventSchedule(&EvDiscoveryReq, NULL);
}
}
/*****************************************************************************
*
* @func UINT | IrlmpConnectReq | Process IRLMP connect request
*
* @rdesc SUCCESS or an error code
*
* @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
*/
UINT
IrlmpConnectReq(IRDA_MSG *pMsg)
{
PIRLMP_LSAP_CB pLsapCb;
PIRLMP_LINK_CB pIrlmpCb = GetIrlmpCb(pMsg->IRDA_MSG_RemoteDevAddr);
UINT rc = SUCCESS;
if (pIrlmpCb == NULL)
return IRLMP_BAD_DEV_ADDR;
LOCK_LINK(pIrlmpCb->pIrdaLinkCb);
if (pIrlmpCb->pExclLsapCb != NULL)
{
rc = IRLMP_IN_EXCLUSIVE_MODE;
}
else if (GetLsap(pIrlmpCb, pMsg->IRDA_MSG_LocalLsapSel,
pMsg->IRDA_MSG_RemoteLsapSel) != NULL)
{
rc = IRLMP_LSAP_SEL_IN_USE;
}
else if ((UINT)pMsg->IRDA_MSG_ConnDataLen > IRLMP_MAX_USER_DATA_LEN)
{
rc = IRLMP_USER_DATA_LEN_EXCEEDED;
}
else if (CreateLsap(pIrlmpCb, &pLsapCb) != SUCCESS)
{
rc = 1;
}
if (rc != SUCCESS)
goto exit;
// Initialize the LSAP endpoint
pLsapCb->LocalLsapSel = pMsg->IRDA_MSG_LocalLsapSel;
pLsapCb->RemoteLsapSel = pMsg->IRDA_MSG_RemoteLsapSel;
pLsapCb->pTdiContext = pMsg->IRDA_MSG_pContext;
pLsapCb->UseTtp = pMsg->IRDA_MSG_UseTtp;
pLsapCb->RxMaxSDUSize = pMsg->IRDA_MSG_MaxSDUSize;
pLsapCb->AvailableCredit = pMsg->IRDA_MSG_TtpCredits;
pLsapCb->UserDataLen = pMsg->IRDA_MSG_ConnDataLen;
RtlCopyMemory(pLsapCb->UserData, pMsg->IRDA_MSG_pConnData,
pMsg->IRDA_MSG_ConnDataLen);
// TDI can abort this connection before the confirm
// from peer is received. TDI will call into LMP to
// do this so we must return the Lsap context now.
// This is the only time we actually return something
// in an Irda Message.
pMsg->IRDA_MSG_pContext = pLsapCb;
DEBUGMSG((DBG_IRLMP | DBG_IRLMP_CONN),
(TEXT("IRLMP: IRLMP_CONNECT_REQ (l=%d,r=%d), Tdi:%X LinkState=%s\r\n"),
pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel, pLsapCb->pTdiContext,
pIrlmpCb->LinkState == LINK_DISCONNECTED ? TEXT("DISCONNECTED") :
pIrlmpCb->LinkState == LINK_IN_DISCOVERY ? TEXT("IN_DISCOVERY") :
pIrlmpCb->LinkState == LINK_DISCONNECTING? TEXT("DISCONNECTING"):
pIrlmpCb->LinkState == LINK_READY ? TEXT("READY") : TEXT("oh!")));
switch (pIrlmpCb->LinkState)
{
case LINK_DISCONNECTED:
RtlCopyMemory(pIrlmpCb->ConnDevAddr, pMsg->IRDA_MSG_RemoteDevAddr,
IRDA_DEV_ADDR_LEN);
pLsapCb->State = LSAP_CONN_REQ_PEND;
SetupTtp(pLsapCb);
// Initiate a connection on another thrd cuz this might be the rx thread
ScheduleConnectReq(pIrlmpCb);
break;
case LINK_IN_DISCOVERY:
case LINK_DISCONNECTING:
if (pIrlmpCb->ConnDevAddrSet == FALSE)
{
// Ensure that only the first device to request a connection
// sets the device address of the remote to be connected to.
RtlCopyMemory(pIrlmpCb->ConnDevAddr, pMsg->IRDA_MSG_RemoteDevAddr,
IRDA_DEV_ADDR_LEN);
pIrlmpCb->ConnDevAddrSet = TRUE;
}
else
{
DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Link in use!\r\n")));
#ifdef UNDER_CE
if (memcmp(pMsg->IRDA_MSG_RemoteDevAddr,
pIrlmpCb->ConnDevAddr,
IRDA_DEV_ADDR_LEN) != 0)
#else
if (RtlCompareMemory(pMsg->IRDA_MSG_RemoteDevAddr,
pIrlmpCb->ConnDevAddr,
IRDA_DEV_ADDR_LEN) != IRDA_DEV_ADDR_LEN)
#endif // !UNDER_CE
{
// This LSAP is requesting a connection to another device
CleanupLsap(pLsapCb);
rc = IRLMP_LINK_IN_USE;
break;
}
}
pLsapCb->State = LSAP_CONN_REQ_PEND;
SetupTtp(pLsapCb);
// This request will complete when discovery/disconnect ends
break;
case LINK_CONNECTING:
#ifdef UNDER_CE
if (memcmp(pMsg->IRDA_MSG_RemoteDevAddr,
pIrlmpCb->ConnDevAddr,
IRDA_DEV_ADDR_LEN) != 0)
#else
if (RtlCompareMemory(pMsg->IRDA_MSG_RemoteDevAddr,
pIrlmpCb->ConnDevAddr,
IRDA_DEV_ADDR_LEN) != IRDA_DEV_ADDR_LEN)
#endif // !UNDER_CE
{
DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Link in use!\r\n")));
// This LSAP is requesting a connection to another device,
// not the one IRLAP is currently connected to
CleanupLsap(pLsapCb);
rc = IRLMP_LINK_IN_USE;
break;
}
// The LSAP will be notified when the IRLAP connection that is
// underway has completed (see IRLAP_ConnectConf)
pLsapCb->State = LSAP_IRLAP_CONN_PEND;
SetupTtp(pLsapCb);
break;
case LINK_READY:
#ifdef UNDER_CE
if (memcmp(pMsg->IRDA_MSG_RemoteDevAddr,
pIrlmpCb->ConnDevAddr,
IRDA_DEV_ADDR_LEN) != 0)
#else
if (RtlCompareMemory(pMsg->IRDA_MSG_RemoteDevAddr,
pIrlmpCb->ConnDevAddr,
IRDA_DEV_ADDR_LEN) != IRDA_DEV_ADDR_LEN)
#endif // !UNDER_CE
{
DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Link in use!\r\n")));
// This LSAP is requesting a connection to another device
CleanupLsap(pLsapCb);
rc = IRLMP_LINK_IN_USE;
break;
}
IrdaTimerRestart(&pLsapCb->ResponseTimer);
pLsapCb->State = LSAP_LMCONN_CONF_PEND;
SetupTtp(pLsapCb);
// Ask remote LSAP for a connection
SendCntlPdu(pLsapCb, IRLMP_CONNECT_PDU,
IRLMP_ABIT_REQUEST, IRLMP_RSVD_PARM, 0);
break;
}
exit:
UNLOCK_LINK(pIrlmpCb->pIrdaLinkCb);
return rc;
}
/*****************************************************************************
*
* @func void | SetupTtp | if using TTP, calculate initial credits
*
* @rdesc SUCCESS or an error code
*
* @parm IRLMP_LSAP_CB * | pLsapCb | pointer LSAP control block
*/
void
SetupTtp(IRLMP_LSAP_CB *pLsapCb)
{
VALIDLSAP(pLsapCb);
if (pLsapCb->AvailableCredit > 127)
{
pLsapCb->RemoteTxCredit = 127;
pLsapCb->AvailableCredit -= 127;
}
else
{
pLsapCb->RemoteTxCredit = pLsapCb->AvailableCredit;
pLsapCb->AvailableCredit = 0;
}
DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: RemoteTxCredit %d\n"),
pLsapCb->RemoteTxCredit));
}
/*****************************************************************************
*
* @func UINT | IrlmpConnectResp | Process IRLMP connect response
*
* @rdesc SUCCESS or an error code
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -