⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l2capdev.cxx

📁 Windows CE操作系统中适用的蓝牙驱动程序
💻 CXX
📖 第 1 页 / 共 4 页
字号:

			gpState->Unlock ();

			L2CAPClosePSM (psm);

			if (! gpState)
				return;

			gpState->Lock ();

			if (! gpState->fIsRunning) {
				gpState->Unlock ();
				return;
			}

			pPort = gpState->pPorts;
			continue;
		}
		pPort = pPort->pNext;
	}
    
    Link *pLink = gpState->pLinks;

	while (pLink) {
		if (pLink->hProcOwner == hProc) {
			unsigned short cid = pLink->cid;
			gpState->Unlock ();

			L2CAPCloseCID (cid);

			if (! gpState)
				return;

			gpState->Lock ();

			if (! gpState->fIsRunning) {
				gpState->Unlock ();
				return;
			}
			pLink = gpState->pLinks;
			continue;
		}

		pLink = pLink->pNext;
	}

	SCall *pCall = gpState->pCalls;
	while (pCall) {
		if ((pCall->hProcOwner == hProc) && (! pCall->fComplete)) {
			if (pCall->fAutoClean) {
				SCall *pNext = pCall->pNext;
				DeleteCall (pCall);
				pCall = pNext;
				continue;
			}

			pCall->fComplete = TRUE;
			pCall->iResult = ERROR_SHUTDOWN_IN_PROGRESS;
			SetEvent (pCall->hEvent);
		}

		pCall = pCall->pNext;
	}

	gpState->Unlock ();
}

//
//	L2CAP stuff
//
static int l2capdev_DataUpInd (void *pUserContext, unsigned short cid, BD_BUFFER *pBuffer) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Data up on channel 0x%04x %d bytes\n", cid, BufferTotal (pBuffer)));

	if (! gpState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpState->Lock ();

	if (! gpState->fIsRunning) {
		gpState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	Link *pLink = FindLink (cid);

	if (pLink) {
		SCall *pCall = gpState->pCalls;
		while (pCall && ((pCall->pLink != pLink) || (pCall->fWhat != CALL_L2CAP_DATA_READ) || pCall->fComplete))
			pCall = pCall->pNext;

		if (! pCall) {
			pCall = AllocCall (CALL_L2CAP_DATA_READ, pLink, pLink->hProcOwner);
			if (! pCall) {
				gpState->Unlock ();
				return ERROR_OUTOFMEMORY;
			}
	
			pCall->fAutoClean = TRUE;
		}

		pCall->pBuffer = pBuffer->fMustCopy ? L2CAP_BufferCopy (pBuffer) : pBuffer;

		pCall->fComplete = TRUE;
		pCall->iResult = ERROR_SUCCESS;
		SetEvent (pCall->hEvent);
	}

	gpState->Unlock ();
	return ERROR_SUCCESS;
}

static int l2capdev_DisconnectInd (void *pUserContext, unsigned short cid, int iError) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Disconnect indicator on channel 0x%04x\n", cid));

	if (! gpState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpState->Lock ();

	if (! gpState->fIsRunning) {
		gpState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	Link *pLink = FindLink (cid);
	if (! pLink) {
		gpState->Unlock ();
		return ERROR_NOT_FOUND;
	}

	if (pLink->fStage == UP) {
		SCall *pC = gpState->pCalls;
		while (pC) {
			if (pC->pLink == pLink) {
				if (pC->fAutoClean) {
					DeleteCall (pC);
					pC = gpState->pCalls;
					continue;
				} else if (! pC->fComplete) {
					pC->fComplete = TRUE;
					pC->iResult = ERROR_CONNECTION_UNAVAIL;
					SetEvent (pC->hEvent);
				}
			}

			pC = pC->pNext;
		}

		pLink->fStage |= LINK_ERROR;
	} else
		DeleteLink (pLink);

	gpState->Unlock ();
	return ERROR_SUCCESS;
}

static int l2capdev_lStackEvent (void *pUserContext, int iEvent, void *pEventContext) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Stack event (L2CAP) %d\n", iEvent));

	if (! gpState)
		return ERROR_SUCCESS;

	gpState->Lock ();

	if (! gpState->fIsRunning) {
		gpState->Unlock ();
		return ERROR_SUCCESS;
	}

	LPTHREAD_START_ROUTINE p = NULL;

	if (iEvent == BTH_STACK_DISCONNECT)
		l2capdev_CloseDriverInstance ();
	else if (iEvent == BTH_STACK_DOWN)
		p = StackDown;
	else if (iEvent == BTH_STACK_UP)
		p = StackUp;

	HANDLE h = p ? CreateThread (NULL, 0, p, NULL, 0, NULL) : NULL;

	if (h) {
		CloseHandle (h);
		gpState->AddRef ();
	}

	gpState->Unlock ();

	return ERROR_SUCCESS;
}

static int l2capdev_lCallAborted (void *pCallContext, int iError) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Aborted call 0x%08x error %d\n", pCallContext, iError));

	if (! gpState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpState->Lock ();

	if (! gpState->fIsRunning) {
		gpState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	SCall *pCall = VerifyCall ((SCall *)pCallContext);
	if (! pCall) {
		gpState->Unlock ();
		return ERROR_NOT_FOUND;
	}

	SVSUTIL_ASSERT (! pCall->fComplete);
	SVSUTIL_ASSERT (! pCall->pBuffer);

	Link *pLink = pCall->pLink;

	if (pCall->fAutoClean)
		DeleteCall (pCall);
	else {
		pCall->iResult = iError;
		pCall->fComplete = TRUE;
		pCall->pLink = NULL;
		SetEvent (pCall->hEvent);
	}

	unsigned short disconnect_cid = 0;

	if (pLink) {
		if ((pLink->fStage & UP) != UP) {
			if (pLink->fStage & CONNECTED)
				disconnect_cid = pLink->cid;
			else 
				DeleteLink (pLink);
		} else
			pLink->fStage |= LINK_ERROR;
	}

	gpState->Unlock ();

	if (disconnect_cid)
		L2CAPCloseCID (disconnect_cid);

	return ERROR_SUCCESS;
}

static int l2capdev_ConfigInd (void *pUserContext, unsigned char id, unsigned short cid, unsigned short usOutMTU, unsigned short usInFlushTO, struct btFLOWSPEC *pInFlow, int cOptNum, struct btCONFIGEXTENSION **pExtendedOptions) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Config request indicator on ch 0x%04x id %d MTU %d flush 0x%04x, flow: %s\n", cid, id, usOutMTU, usInFlushTO, pInFlow ? L"yes" : L"no"));

	if (! gpState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpState->Lock ();

	if (! gpState->fIsRunning) {
		gpState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	Link *pLink = FindLink (cid);
	SCall *pCall = pLink ? FindCall (pLink, CALL_L2CAP_LINK_SETUP) : NULL;

	if ((! pCall) || pCall->fComplete)  {
		gpState->Unlock ();
		return ERROR_NOT_FOUND;
	}

	SVSUTIL_ASSERT (pCall->fWhat == CALL_L2CAP_LINK_SETUP);
	SVSUTIL_ASSERT (! pCall->fComplete);
	SVSUTIL_ASSERT (VerifyLink (pCall->pLink));
	SVSUTIL_ASSERT (! pCall->pBuffer);

	int fAccept = FALSE;

	if ((usInFlushTO == 0xffff) && (! pInFlow)) {
		pCall->iResult = ERROR_SUCCESS;
		pCall->pLink->fStage |= CONFIG_IND_DONE;
		pCall->pLink->outMTU = usOutMTU;
		fAccept = TRUE;

		if (pLink->fStage == UP) {
			if (pLink->fIncoming) {
				SVSUTIL_ASSERT (pCall->fAutoClean);
				pCall->fComplete = TRUE;

				SCall *pCall2 = gpState->pCalls;
				while (pCall2 && (pCall2->fComplete || (pCall2->fWhat != CALL_L2CAP_ACCEPT) || (pCall2->psm != pLink->psm)))
					pCall2 = pCall2->pNext;

				if (pCall2) {
					DeleteCall (pCall);
					pCall2->fComplete = TRUE;
					pCall2->iResult = ERROR_SUCCESS;
					pCall2->pLink   = pLink;
					SetEvent (pCall2->hEvent);
				}
			} else {
				pCall->fComplete = TRUE;
				pCall->iResult = ERROR_SUCCESS;
				SetEvent (pCall->hEvent);
			}
		}
	}

	HANDLE hL2CAP = gpState->hL2CAP;
	L2CA_ConfigResponse_In pCallback = gpState->l2cap_if.l2ca_ConfigResponse_In;
	gpState->Unlock ();

	__try {
		pCallback (hL2CAP, NULL, id, cid, fAccept ? 0 : 2, 0, 0xffff, NULL, 0, NULL);
	} __except (1) {
	}

	if (! fAccept)
		l2capdev_lCallAborted (pCall, ERROR_CONNECTION_ABORTED);

	return ERROR_SUCCESS;
}

static int l2capdev_ConfigReq_Out (void *pCallContext, unsigned short usResult, unsigned short usInMTU, unsigned short usOutFlushTO, struct btFLOWSPEC *pOutFlow, int cOptNum, struct btCONFIGEXTENSION **pExtendedOptions) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Config req out for call 0x%08x result 0x%04x mtu %d flush 0x%04x, flow %s\n", pCallContext, usResult, usInMTU, usOutFlushTO, pOutFlow ? L"yes" : L"no" ));

	if (! gpState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpState->Lock ();

	if (! gpState->fIsRunning) {
		gpState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	SCall *pCall = VerifyCall ((SCall *)pCallContext);
	if ((! pCall) || pCall->fComplete)  {
		gpState->Unlock ();
		return ERROR_NOT_FOUND;
	}

	SVSUTIL_ASSERT (pCall->fWhat == CALL_L2CAP_LINK_SETUP);
	SVSUTIL_ASSERT (! pCall->fComplete);
	SVSUTIL_ASSERT (VerifyLink (pCall->pLink));
	SVSUTIL_ASSERT (! pCall->pBuffer);

	if (usResult == 0) {
		Link *pLink = pCall->pLink;
		SVSUTIL_ASSERT (! (pLink->fStage & CONFIG_REQ_DONE));
		SVSUTIL_ASSERT (pLink->fStage & CONNECTED);
		SVSUTIL_ASSERT (pLink->cid);
		SVSUTIL_ASSERT (pLink->psm);
		SVSUTIL_ASSERT (pLink->hProcOwner);

		pLink->fStage |= CONFIG_REQ_DONE;

		if (pLink->fStage == UP) {
			if (pLink->fIncoming) {
				SVSUTIL_ASSERT (pCall->fAutoClean);
				pCall->fComplete = TRUE;

				SCall *pCall2 = gpState->pCalls;
				while (pCall2 && (pCall2->fComplete || (pCall2->fWhat != CALL_L2CAP_ACCEPT) || (pCall2->psm != pLink->psm)))
					pCall2 = pCall2->pNext;

				if (pCall2) {
					DeleteCall (pCall);
					pCall2->fComplete = TRUE;
					pCall2->iResult = ERROR_SUCCESS;
					pCall2->pLink   = pLink;
					SetEvent (pCall2->hEvent);
				}
			} else {
				pCall->fComplete = TRUE;
				pCall->iResult = ERROR_SUCCESS;
				SetEvent (pCall->hEvent);
			}
		}

		gpState->Unlock ();
		return ERROR_SUCCESS;
	}
	gpState->Unlock ();

	l2capdev_lCallAborted (pCallContext, ERROR_CONNECTION_ABORTED);

	return ERROR_SUCCESS;
}

static int l2capdev_ConnectInd (void *pUserContext, BD_ADDR *pba, unsigned short cid, unsigned char id, unsigned short psm) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Connect indicator from %04x%08x ch 0x%04x id %d psm 0x%04x\n", pba->NAP, pba->SAP, cid, id, psm));

	if (! gpState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpState->Lock ();

	if (! gpState->fIsRunning) {
		gpState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	Port *pPort = gpState->pPorts;
	while (pPort && (pPort->psm != psm))
		pPort = pPort->pNext;

	unsigned short	result;
	unsigned short	status = 0;
	unsigned short	mtu = 0;
	SCall *pCall = NULL;

	if (pPort) {
		Link *pLink = (Link *)svsutil_GetFixed (gpState->pfmdLinks);
		pCall = pLink ? AllocCall (CALL_L2CAP_LINK_SETUP, pLink, pPort->hProcOwner) : NULL;
		if (pCall) {
			pCall->fAutoClean = TRUE;

			pLink->b = *pba;
			pLink->cid = cid;
			pLink->fStage = CONNECTED;
			pLink->hProcOwner = pPort->hProcOwner;
			pLink->inMTU = pPort->mtu;
			pLink->outMTU = 0;
			pLink->psm = psm;
			pLink->fIncoming = TRUE;

			pLink->pNext = gpState->pLinks;
			gpState->pLinks = pLink;

			result = 0;
			mtu = pPort->mtu;
		} else {
			if (pLink)
				svsutil_FreeFixed (pLink, gpState->pfmdLinks);
			result = 4;
		}
	} else
		result = 2;

	HANDLE hL2CAP = gpState->hL2CAP;
	L2CA_ConnectResponse_In pCallbackConnect = gpState->l2cap_if.l2ca_ConnectResponse_In;
	L2CA_ConfigReq_In pCallbackConfig = gpState->l2cap_if.l2ca_ConfigReq_In;
	gpState->Unlock ();

	__try {
		pCallbackConnect (hL2CAP, NULL, pba, id, cid, result, status);
	} __except (1) {
	}

	if (result == 0) {
		int iRes = ERROR_INTERNAL_ERROR;
		__try {
			iRes = pCallbackConfig (hL2CAP, pCall, cid, mtu, 0xffff, NULL, 0, NULL);
		} __except (1) {
		}

		if (iRes != ERROR_SUCCESS)
			l2capdev_lCallAborted (pCall, iRes);
	}

	return ERROR_SUCCESS;
}

static int l2capdev_ConnectReq_Out (void *pCallContext, unsigned short cid, unsigned short result, unsigned short status) {
	IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Connect out for call 0x%08x ch 0x%04x result = 0x%04x status 0x%04x\n", pCallContext, cid, result, status));

	if (! gpState)
		return ERROR_SERVICE_NOT_ACTIVE;

	gpState->Lock ();

	if (! gpState->fIsRunning) {
		gpState->Unlock ();
		return ERROR_SERVICE_NOT_ACTIVE;
	}

	SCall *pCall = VerifyCall ((SCall *)pCallContext);
	if ((! pCall) || pCall->fComplete) {
		gpState->Unlock ();
		return ERROR_NOT_FOUND;
	}

	SVSUTIL_ASSERT (pCall->fWhat == CALL_L2CAP_LINK_SETUP);
	SVSUTIL_ASSERT (! pCall->fComplete);
	SVSUTIL_ASSERT (VerifyLink (pCall->pLink));
	SVSUTIL_ASSERT (! pCall->pBuffer);

	if (result) {
		if (result != 1) {
			pCall->fComplete = TRUE;
			pCall->iResult = ERROR_CONNECTION_REFUSED;
			SetEvent (pCall->hEvent);
		}
		gpState->Unlock ();
		return ERROR_SUCCESS;
	}

	Link *pLink = pCall->pLink;

	SVSUTIL_ASSERT (pLink->fStage == NONE);
	SVSUTIL_ASSERT (! pLink->cid);
	SVSUTIL_ASSERT (pLink->psm);
	SVSUTIL_ASSERT (pLink->hProcOwner);

	pLink->fStage = CONNECTED;
	pLink->cid = cid;

	unsigned short mtu = pLink->inMTU;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -