📄 l2cap.cxx
字号:
static DWORD WINAPI CallTimeout (LPVOID pArg) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"CallTimeout\n"));
if (! gpL2CAP) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"CallTimeout : shutting down!\n"));
return 0;
}
gpL2CAP->Lock ();
if (gpL2CAP->eStage != Connected) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"CallTimeout : shutting down!\n"));
gpL2CAP->Unlock ();
return 0;
}
CallContext *pCall = VerifyCall ((CallContext *)pArg);
if (! pCall) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"CallTimeout : no call!\n"));
gpL2CAP->Unlock ();
return 0;
}
if (pCall->dwTimeOutCookie != 0) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"CallTimeout : timeouting the call\n"));
pCall->dwTimeOutCookie = 0;
if (pCall->eWhat == CALL_LOG_DISCONNECT_REQ) {
SVSUTIL_ASSERT (VerifyLog (pCall->u.pLogLink));
LogLink *pLog = pCall->u.pLogLink;
CancelCall (pCall, ERROR_TIMEOUT);
if (VerifyLog (pLog))
DisconnectLogicalLink (pLog, ERROR_TIMEOUT, FALSE);
} else if (pCall->eWhat == CALL_PHYS_PING) {
SVSUTIL_ASSERT (VerifyPhys (pCall->u.pPhysLink));
PhysLink *pPhys = pCall->u.pPhysLink;
CancelCall (pCall, ERROR_TIMEOUT);
if (VerifyPhys (pPhys))
DisconnectPhysicalLink (pPhys, FALSE, ERROR_TIMEOUT, NULL);
} else
SVSUTIL_ASSERT (0);
}
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"CallTimeout : done\n"));
gpL2CAP->Unlock ();
return 0;
}
static void ScheduleTimeout (PhysLink *pLink, DWORD dwTime) {
if (pLink->dwTimeOutCookie)
btutil_UnScheduleEvent (pLink->dwTimeOutCookie);
pLink->dwTimeOutCookie = btutil_ScheduleEvent (PhysLinkTimeout, pLink, dwTime * 1000);
}
static void ScheduleTimeout (LogLink *pLink, DWORD dwTime) {
if (pLink->dwTimeOutCookie)
btutil_UnScheduleEvent (pLink->dwTimeOutCookie);
pLink->dwTimeOutCookie = btutil_ScheduleEvent (LogLinkTimeout, pLink, dwTime * 1000);
}
static void ScheduleTimeout (CallContext *pCall, DWORD dwTime) {
if (pCall->dwTimeOutCookie)
btutil_UnScheduleEvent (pCall->dwTimeOutCookie);
pCall->dwTimeOutCookie = btutil_ScheduleEvent (CallTimeout, pCall, dwTime * 1000);
}
static void UnscheduleTimeout (PhysLink *pLink) {
if (pLink->dwTimeOutCookie)
btutil_UnScheduleEvent (pLink->dwTimeOutCookie);
pLink->dwTimeOutCookie = 0;
}
static void UnscheduleTimeout (LogLink *pLink) {
if (pLink->dwTimeOutCookie)
btutil_UnScheduleEvent (pLink->dwTimeOutCookie);
pLink->dwTimeOutCookie = 0;
}
static void UnscheduleTimeout (CallContext *pCall) {
if (pCall->dwTimeOutCookie)
btutil_UnScheduleEvent (pCall->dwTimeOutCookie);
pCall->dwTimeOutCookie = 0;
}
//
// Communicate stack event up
//
static void DispatchStackEvent (int iEvent) {
L2CAP_CONTEXT *pContext = gpL2CAP->pContexts;
while (pContext && gpL2CAP->IsStackRunning ()) {
BT_LAYER_STACK_EVENT_IND pCallback = pContext->ei.l2ca_StackEvent;
if (pCallback) {
void *pUserContext = pContext->pUserContext;
IFDBG(DebugOut (DEBUG_L2CAP_CALLBACK, L"Going into StackEvent notification\n"));
pContext->AddRef ();
gpL2CAP->Unlock ();
__try {
pCallback (pUserContext, iEvent, NULL);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"[L2CAP] L2CAP_connect_transport: exception in L2CAP_StackEvent!\n"));
}
gpL2CAP->Lock ();
pContext->DelRef ();
IFDBG(DebugOut (DEBUG_L2CAP_CALLBACK, L"Came back StackEvent notification\n"));
}
pContext = pContext->pNext;
}
}
static DWORD WINAPI StackDown (LPVOID pArg) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"Disconnect stack\n"));
for ( ; ; ) {
if (! gpL2CAP) {
IFDBG(DebugOut (DEBUG_ERROR, L"[L2CAP] DisconnectStack:: ERROR_SERVICE_DOES_NOT_EXIST\n"));
return ERROR_SERVICE_DOES_NOT_EXIST;
}
gpL2CAP->Lock ();
if (gpL2CAP->eStage != Connected) {
IFDBG(DebugOut (DEBUG_ERROR, L"[L2CAP] DisconnectStack:: ERROR_SERVICE_ALREADY_RUNNING\n"));
gpL2CAP->Unlock ();
return ERROR_SERVICE_ALREADY_RUNNING;
}
if (gpL2CAP->GetRefCount () == 1)
break;
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"Waiting for ref count in StackDown\n"));
gpL2CAP->Unlock ();
Sleep (100);
}
gpL2CAP->iEchoes = 0;
gpL2CAP->eStage = Disconnected;
gpL2CAP->AddRef ();
while (gpL2CAP->pPhysLinks && gpL2CAP->IsStackRunning ()) {
gpL2CAP->pPhysLinks->eStage = DISCONNECTED;
DisconnectPhysicalLink (gpL2CAP->pPhysLinks, FALSE, ERROR_SHUTDOWN_IN_PROGRESS, NULL);
}
while (gpL2CAP->pCalls && gpL2CAP->IsStackRunning ())
AbortCall (gpL2CAP->pCalls, ERROR_SHUTDOWN_IN_PROGRESS);
DispatchStackEvent (BTH_STACK_DOWN);
gpL2CAP->DelRef ();
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"DisconnectStack:: ERROR_SUCCESS\n"));
gpL2CAP->Unlock ();
return ERROR_SUCCESS;
}
static DWORD WINAPI StackUp (LPVOID pArg) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"Connect stack\n"));
for ( ; ; ) {
if (! gpL2CAP) {
IFDBG(DebugOut (DEBUG_ERROR, L"[L2CAP] ConnectStack:: ERROR_SERVICE_DOES_NOT_EXIST\n"));
return ERROR_SERVICE_DOES_NOT_EXIST;
}
gpL2CAP->Lock ();
if (gpL2CAP->eStage != Disconnected) {
IFDBG(DebugOut (DEBUG_ERROR, L"[L2CAP] ConnectStack:: ERROR_SERVICE_ALREADY_RUNNING\n"));
gpL2CAP->Unlock ();
return ERROR_SERVICE_ALREADY_RUNNING;
}
if (gpL2CAP->GetRefCount () == 1)
break;
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"Waiting for ref count in StackUp\n"));
gpL2CAP->Unlock ();
Sleep (100);
}
gpL2CAP->AddRef ();
gpL2CAP->eStage = Connected;
SetScanEnable ();
DispatchStackEvent (BTH_STACK_UP);
gpL2CAP->DelRef ();
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"ConnectStack:: ERROR_SUCCESS\n"));
gpL2CAP->Unlock ();
return ERROR_SUCCESS;
}
static DWORD WINAPI StackReset (LPVOID pArg) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"Reset stack\n"));
StackDown (NULL);
StackUp (NULL);
return NULL;
}
static DWORD WINAPI StackDisconnect (LPVOID pArg) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"Disconnect stack\n"));
l2cap_CloseDriverInstance ();
return NULL;
}
static BOOL IsModeChangeEvent (unsigned char *p, int c) {
if ((c >= 8) && // Ensure size is large enough to be a mode change
(p[0] == HCI_Mode_Change_Event) && // Is a mode change
(p[2] == 0)) // Status of mode change is success
{
return TRUE;
}
return FALSE;
}
static void UnParkIfNeeded (PhysLink* pPhysLink) {
if (pPhysLink->mode == 0x03) {
BT_ADDR bta = SET_NAP_SAP(pPhysLink->b.NAP, pPhysLink->b.SAP);
BthExitParkMode (&bta);
}
}
//
// The MEAT
//
static void AbortCall (CallContext *pCall, int iErr) {
pCall->fComplete = TRUE;
pCall->iResult = iErr;
int fDel = ! pCall->fKeepOnAbort;
if (pCall->eType == CALL_CTX_EVENT) {
SetEvent (pCall->hEvent);
} else if (pCall->eType == CALL_CTX_CALLBACK) {
__try {
pCall->pCallback (pCall, iErr);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"CALL_CTX_CALLBACK :: Excepted in AbortCall while processing callbacl\n"));
}
} else if (pCall->eType == CALL_CTX_CALLOWNER) {
L2CAP_CONTEXT *pContext = VerifyContext (pCall->pOwner);
if (pContext && pContext->c.l2ca_CallAborted) {
BT_LAYER_CALL_ABORTED pCallback = pContext->c.l2ca_CallAborted;
void *pCallContext = pCall->pContext;
pContext->AddRef ();
IFDBG(DebugOut (DEBUG_L2CAP_CALLBACK, L"AbortCall:: going in callback\n"));
gpL2CAP->Unlock ();
__try {
pCallback (pCallContext, iErr);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"CALL_CTX_CALLOWNER :: Excepted in AbortCall while processing callbacl\n"));
}
gpL2CAP->Lock ();
IFDBG(DebugOut (DEBUG_L2CAP_CALLBACK, L"AbortCall:: back from callback\n"));
pContext->DelRef ();
}
} else if (pCall->eType == CALL_CTX_INTERNAL)
;
else
SVSUTIL_ASSERT (0);
if (fDel && gpL2CAP->IsStackRunning ())
DeleteCallContext (pCall);
}
static void DisconnectLogicalLink (LogLink *pThis, int iErr, int fSendDisconnect) {
// Take it out of the list
if (! PluckLogLink (pThis)) {
IFDBG(DebugOut (DEBUG_ERROR, L"Disconnecting non-existent link!\n"));
return;
}
UnscheduleTimeout (pThis);
if (! pThis->pPhysLink->pLogLinks)
ScheduleTimeout (pThis->pPhysLink, gpL2CAP->dwPhysIdle);
CallContext *pCall;
// Cancel all calls to it...
while ((gpL2CAP->IsStackRunning ()) && (pCall = FindCall (pThis)))
AbortCall (pCall, iErr);
if (! gpL2CAP->IsStackRunning ())
return;
unsigned short cid = pThis->cid;
unsigned short cid_remote = pThis->cid_remote;
unsigned short h = (pThis->pPhysLink && (pThis->pPhysLink->eStage == UP)) ? pThis->pPhysLink->h : BT_HCI_INVALID_HANDLE;
L2CAP_CONTEXT *pOwner = VerifyContext (pThis->pOwner);
// Delete the thing.
delete pThis;
// Signal disconnection, if required
if (cid && pOwner && pOwner->ei.l2ca_DisconnectInd) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"DisconnectLogicalLink :: closing cid 0x%04x\n", cid));
IFDBG(DebugOut (DEBUG_L2CAP_CALLBACK, L"DisconnectLogicalLink:: going into callback\n"));
pOwner->AddRef ();
gpL2CAP->Unlock ();
__try {
pOwner->ei.l2ca_DisconnectInd (pOwner->pUserContext, cid, iErr);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"DisconnectLogicalLink:: Exception in callback l2ca_DisconnectInd!\n"));
}
gpL2CAP->Lock ();
pOwner->DelRef ();
IFDBG(DebugOut (DEBUG_L2CAP_CALLBACK, L"DisconnectLogicalLink:: Back from callback\n"));
}
if ((gpL2CAP->eStage == Connected) && fSendDisconnect && (cid_remote != INVALID_CID) && (h != BT_HCI_INVALID_HANDLE)) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"Sending disconnect signal\n"));
Signal s;
s.cid = 1;
s.length = sizeof(s.packet.h) + sizeof(s.packet.u.DISCONNECT_REQUEST);
s.packet.h.code = L2CAP_COMMAND_DISCONNECT_REQUEST;
s.packet.h.id = gpL2CAP->ucCurrentID++;
if (! s.packet.h.id)
s.packet.h.id = gpL2CAP->ucCurrentID++;
s.packet.h.length = sizeof(s.packet.u.DISCONNECT_REQUEST);
s.packet.u.DISCONNECT_REQUEST.dest_cid = cid_remote;
s.packet.u.DISCONNECT_REQUEST.source_cid = cid;
int iRes = WriteDataDown (h, NULL, SIGNAL_LENGTH(s), (unsigned char *)&s);
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"WriteDataDown returns %d\n", iRes));
}
}
static int DisconnectPhysicalLink (PhysLink *pPhysLink, int fReconnect, int iErr, CallContext *pCallContext) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"DisconnectPhysicalLink :: %04x%08x reconnect = %d\n", pPhysLink->b.NAP, pPhysLink->b.SAP, fReconnect));
SVSUTIL_ASSERT((! pCallContext) || (! fReconnect));
UnscheduleTimeout (pPhysLink);
if ((pPhysLink->iConnectionAttempts > L2CAP_RECONNECT) || (gpL2CAP->eStage == Disconnected))
fReconnect = FALSE;
if (! fReconnect)
PluckPhysLink (pPhysLink);
while (gpL2CAP->IsStackRunning () && pPhysLink->pLogLinks) {
SVSUTIL_ASSERT (! pCallContext);
LogLink *pThis = pPhysLink->pLogLinks;
if (fReconnect) {
while (pThis && ((pThis->eStage == STARTING) || (pThis->eStage == STARTING_PHYS)))
pThis = pThis->pNext;
if (! pThis)
break;
}
DisconnectLogicalLink (pThis, iErr, FALSE);
}
if (! gpL2CAP->IsStackRunning ())
return ERROR_SHUTDOWN_IN_PROGRESS;
if (fReconnect && (! pPhysLink->pLogLinks)) {
fReconnect = FALSE;
PluckPhysLink (pPhysLink);
}
if (! fReconnect) {
CallContext *pCall;
while (gpL2CAP->IsStackRunning () && (pCall = FindCall (pPhysLink))) {
SVSUTIL_ASSERT (! pCallContext);
AbortCall (pCall, iErr);
}
if (gpL2CAP->eStage == Connected) {
unsigned short h = pPhysLink->h;
HCI_Disconnect_In pCallback = (pPhysLink->eStage == UP) ? gpL2CAP->hci_if.hci_Disconnect_In : NULL;
HANDLE hHCI = gpL2CAP->hHCI;
IFDBG(BD_ADDR b = pPhysLink->b);
delete pPhysLink;
if (pCallback) {
IFDBG(DebugOut (DEBUG_L2CAP_TRACE, L"Taking down connection to %04x%08x handle 0x%04x\n", b.NAP, b.SAP, h));
IFDBG(DebugOut (DEBUG_L2CAP_CALLBACK, L"Going into hci_Disconnect_In callback\n"));
gpL2CAP->AddRef ();
gpL2CAP->Unlock ();
int iRes = ERROR_INTERNAL_ERROR;
__try {
iRes = pCallback (hHCI, pCallContext, h, 0x13);
} __except (1) {
IFDBG(DebugOut (DEBUG_ERROR, L"Exception in hci_Disconnect_In\n"));
}
gpL2CAP->Lock ();
gpL2CAP->DelRef ();
IFDBG(DebugOut (DEBUG_L2CAP_CALLBACK, L"Came from hci_Disconnect_In callback\n"));
return gpL2CAP->eStage == Connected ? iRes : ERROR_SHUTDOWN_IN_PROGRESS;
}
return ERROR_SUCCESS;
}
return ERROR_SHUTDOWN_IN_PROGRESS;
}
SVSUTIL_ASSERT (! pCallContext);
++pPhysLink->iConnectionAttempts;
pPhysLink->eStage = STARTING;
pPhysLink->h = BT_HCI_INVALID_HANDLE;
pPhysLink->iPingsSent = 0;
pPhysLink->iTransmissionProblems = 0;
pPhysLink->dwTimeOutCookie = 0;
LogLink *pLog = pPhysLink->pLogLinks;
while (pLog) {
SVSUTIL_ASSERT ((pLog->eStage == STARTING) || (pLog->eStage == STARTING_PHYS));
pLog->cid = 0;
pLog->eStage = STARTING_PHYS;
pLog = pLog->pNext;
}
BD_ADDR b = pPhysLink->b;
HANDLE hHCI = gpL2CAP->hHCI;
HCI_CreateConnection_In pHCICall = gpL2CAP->hci_if.hci_CreateConnection_In;
unsigned short usPacketType = pPhysLink->usPacketType ? pPhysLink->usPacketType : gpL2CAP->usPacketType;
BT_LAYER_IO_CONTROL pIoctl = gpL2CAP->hci_if.hci_ioctl;
int iRes = ERROR_INTERNAL_ERROR;
CallContext *pCall = FindCall (pPhysLink, CALL_PHYS_CONNECT); // Must!
if (pCall) {
IFDBG(DebugOut (DEBUG_HCI_CALLBACK, L"going into in hci_CreateConnection_In\n"));
gpL2CAP->AddRef ();
gpL2CAP->Unlock ();
__try {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -