📄 l2capdev.cxx
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/**
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Abstract:
Windows CE Bluetooth stack layer sample
**/
#include <windows.h>
#include <svsutil.hxx>
#include <bt_debug.h>
#include <bt_os.h>
#include <bt_buffer.h>
#include <bt_ddi.h>
#include <bt_api.h>
#if defined (UNDER_CE)
#include <pkfuncs.h>
#endif
#include <bt_tdbg.h>
#include "../l2capapi/l2capapi.hxx"
#include "l2capdev.hxx"
#define DEBUG_LAYER_TRACE 0x00000040
DECLARE_DEBUG_VARS();
#define CALL_L2CAP_LINK_SETUP 0x11
#define CALL_L2CAP_ACCEPT 0x12
#define CALL_L2CAP_DATA_WRITE 0x13
#define CALL_L2CAP_DATA_READ 0x14
#define CALL_L2CAP_DISCONNECT 0x15
#define CALL_L2CAP_PING 0x16
#define NONE 0x00
#define CONNECTED 0x01
#define CONFIG_REQ_DONE 0x02
#define CONFIG_IND_DONE 0x04
#define UP 0x07
#define LINK_ERROR 0x80
struct Link {
Link *pNext;
BD_ADDR b;
unsigned short psm;
unsigned short cid;
unsigned int fStage;
unsigned int fIncoming : 1;
unsigned short inMTU;
unsigned short outMTU;
HANDLE hProcOwner;
};
struct Port {
Port *pNext;
unsigned short psm;
unsigned short mtu;
HANDLE hProcOwner;
};
struct SCall {
SCall *pNext;
Link *pLink;
HANDLE hProcOwner;
HANDLE hEvent;
int iResult;
unsigned short psm;
unsigned int fWhat : 8;
unsigned int fComplete : 1;
unsigned int fAutoClean : 1;
BD_BUFFER *pBuffer;
};
int l2capdev_CloseDriverInstance (void);
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);
static int l2capdev_ConnectInd (void *pUserContext, BD_ADDR *pba, unsigned short cid, unsigned char id, unsigned short psm);
static int l2capdev_DataUpInd (void *pUserContext, unsigned short cid, BD_BUFFER *pBuffer);
static int l2capdev_DisconnectInd (void *pUserContext, unsigned short cid, int iError);
static int l2capdev_lStackEvent (void *pUserContext, int iEvent, void *pEventContext);
static int l2capdev_lCallAborted (void *pCallContext, int iError);
static int l2capdev_ConfigReq_Out (void *pCallContext, unsigned short usResult, unsigned short usInMTU, unsigned short usOutFlushTO, struct btFLOWSPEC *pOutFlow, int cOptNum, struct btCONFIGEXTENSION **pExtendedOptions);
static int l2capdev_ConfigResponse_Out (void *pCallContext, unsigned short result);
static int l2capdev_ConnectReq_Out (void *pCallContext, unsigned short cid, unsigned short result, unsigned short status);
static int l2capdev_ConnectResponse_Out (void *pCallContext, unsigned short result);
static int l2capdev_DataDown_Out (void *pCallContext, unsigned short result);
static int l2capdev_Ping_Out (void *pCallContext, BD_ADDR *pba, unsigned char *pOutBuffer, unsigned short size);
static int l2capdev_Disconnect_Out (void *pCallContext, unsigned short result);
class L2CAPDEV : public SVSSynch, public SVSRefObj {
public:
Link *pLinks;
Port *pPorts;
SCall *pCalls;
unsigned int fIsRunning : 1;
unsigned int fConnected : 1;
HANDLE hL2CAP;
L2CAP_INTERFACE l2cap_if;
int cHeaders;
int cTrailers;
FixedMemDescr *pfmdLinks;
FixedMemDescr *pfmdPorts;
FixedMemDescr *pfmdCalls;
L2CAPDEV (void) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: new L2CAPDEV\n"));
pLinks = NULL;
pPorts = NULL;
pCalls = NULL;
cHeaders = 0;
cTrailers = 0;
fIsRunning = FALSE;
fConnected = FALSE;
hL2CAP = NULL;
memset (&l2cap_if, 0, sizeof(l2cap_if));
pfmdLinks = pfmdPorts = pfmdCalls = NULL;
if (! (pfmdLinks = svsutil_AllocFixedMemDescr (sizeof(Link), 10)))
return;
if (! (pfmdPorts = svsutil_AllocFixedMemDescr (sizeof(Port), 10)))
return;
if (! (pfmdCalls = svsutil_AllocFixedMemDescr (sizeof(SCall), 10)))
return;
L2CAP_EVENT_INDICATION lei;
memset (&lei, 0, sizeof(lei));
lei.l2ca_ConfigInd = l2capdev_ConfigInd;
lei.l2ca_ConnectInd = l2capdev_ConnectInd;
lei.l2ca_DataUpInd = l2capdev_DataUpInd;
lei.l2ca_DisconnectInd = l2capdev_DisconnectInd;
lei.l2ca_StackEvent = l2capdev_lStackEvent;
L2CAP_CALLBACKS lc;
memset (&lc, 0, sizeof(lc));
lc.l2ca_CallAborted = l2capdev_lCallAborted;
lc.l2ca_ConfigReq_Out = l2capdev_ConfigReq_Out;
lc.l2ca_ConfigResponse_Out = l2capdev_ConfigResponse_Out;
lc.l2ca_ConnectReq_Out = l2capdev_ConnectReq_Out;
lc.l2ca_ConnectResponse_Out = l2capdev_ConnectResponse_Out;
lc.l2ca_DataDown_Out = l2capdev_DataDown_Out;
lc.l2ca_Ping_Out = l2capdev_Ping_Out;
lc.l2ca_Disconnect_Out = l2capdev_Disconnect_Out;
if (ERROR_SUCCESS != L2CAP_EstablishDeviceContext (this, L2CAP_PSM_MULTIPLE, &lei, &lc, &l2cap_if, &cHeaders, &cTrailers, &hL2CAP))
return;
fIsRunning = TRUE;
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: new L2CAPDEV successful\n"));
}
~L2CAPDEV (void) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: delete L2CAPDEV\n"));
if (hL2CAP)
L2CAP_CloseDeviceContext (hL2CAP);
if (pfmdLinks)
svsutil_ReleaseFixedNonEmpty (pfmdLinks);
if (pfmdPorts)
svsutil_ReleaseFixedNonEmpty (pfmdPorts);
if (pfmdCalls)
svsutil_ReleaseFixedNonEmpty (pfmdCalls);
}
};
static L2CAPDEV *gpState = NULL;
//
// Auxiliary code
//
static L2CAPDEV *CreateNewState (void) {
return new L2CAPDEV;
}
static SCall *AllocCall (int fWhat, Link *pLink, HANDLE hProcOwner) {
SCall *pCall = (SCall *)svsutil_GetFixed (gpState->pfmdCalls);
if (! pCall)
return NULL;
memset (pCall, 0, sizeof(*pCall));
pCall->pLink = pLink;
pCall->hProcOwner = hProcOwner;
pCall->fWhat = fWhat;
pCall->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
if (NULL == pCall->hEvent) {
svsutil_FreeFixed (pCall, gpState->pfmdCalls);
return NULL;
}
if (! gpState->pCalls)
gpState->pCalls = pCall;
else {
SCall *pLast = gpState->pCalls;
while (pLast->pNext)
pLast = pLast->pNext;
pLast->pNext = pCall;
}
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: Allocated call 0x%08x what = 0x%02x\n", pCall, fWhat));
return pCall;
}
static void DeleteCall (SCall *pCall) {
if (pCall == gpState->pCalls)
gpState->pCalls = pCall->pNext;
else {
SCall *pParent = gpState->pCalls;
while (pParent && (pParent->pNext != pCall))
pParent = pParent->pNext;
if (! pParent) {
IFDBG(DebugOut (DEBUG_ERROR, L"Shell: call not in list in DeleteCall!\n"));
return;
}
pParent->pNext = pCall->pNext;
}
CloseHandle (pCall->hEvent);
if (pCall->pBuffer)
pCall->pBuffer->pFree (pCall->pBuffer);
svsutil_FreeFixed (pCall, gpState->pfmdCalls);
}
static SCall *VerifyCall (SCall *pCall) {
SCall *p = gpState->pCalls;
while (p && (p != pCall))
p = p->pNext;
#if defined (DEBUG) || defined (_DEBUG) || defined (RETAILLOG)
if (! p)
IFDBG(DebugOut (DEBUG_ERROR, L"Shell: call verify failed!\n"));
#endif
return p;
}
static SCall *FindCall (unsigned int fOp) {
SCall *p = gpState->pCalls;
while (p && (p->fWhat != fOp))
p = p->pNext;
#if defined (DEBUG) || defined (_DEBUG) || defined (RETAILLOG)
if (! p)
IFDBG(DebugOut (DEBUG_ERROR, L"Shell: call find failed!\n"));
#endif
return p;
}
static SCall *FindCall (Link *pLink, unsigned int fOp) {
SCall *p = gpState->pCalls;
while (p && ((p->pLink != pLink) || (p->fWhat != fOp)))
p = p->pNext;
#if defined (DEBUG) || defined (_DEBUG) || defined (RETAILLOG)
if (! p)
IFDBG(DebugOut (DEBUG_ERROR, L"Shell: call verify failed!\n"));
#endif
return p;
}
static Link *VerifyLink (Link *pLink) {
Link *p = gpState->pLinks;
while (p && (p != pLink))
p = p->pNext;
#if defined (DEBUG) || defined (_DEBUG) || defined (RETAILLOG)
if (! p)
IFDBG(DebugOut (DEBUG_ERROR, L"Shell: link verify failed!\n"));
#endif
return p;
}
static void DeleteLink (Link *pLink) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: delete link for bd_addr %04x%08x cid 0x%04x\n", pLink->b.NAP, pLink->b.SAP, pLink->cid));
if (pLink == gpState->pLinks)
gpState->pLinks = pLink->pNext;
else {
Link *pParent = gpState->pLinks;
while (pParent && (pParent->pNext != pLink))
pParent = pParent->pNext;
if (! pParent) {
IFDBG(DebugOut (DEBUG_ERROR, L"Shell: link to be deleted not in list\n"));
return;
}
pParent->pNext = pLink->pNext;
}
SCall *pC = gpState->pCalls;
while (pC) {
if (pC->pLink == pLink) {
if (pC->fAutoClean) {
DeleteCall (pC);
pC = gpState->pCalls;
continue;
} else if (! pC->fComplete) {
pC->pLink = NULL;
pC->fComplete = TRUE;
pC->iResult = ERROR_CONNECTION_UNAVAIL;
SetEvent (pC->hEvent);
} else {
pC->pLink = NULL;
if (pC->iResult == ERROR_SUCCESS)
pC->iResult = ERROR_CONNECTION_UNAVAIL;
}
}
pC = pC->pNext;
}
svsutil_FreeFixed (pLink, gpState->pfmdLinks);
}
static Link *FindLink (unsigned short cid) {
Link *p = gpState->pLinks;
while (p && (p->cid != cid))
p = p->pNext;
#if defined (DEBUG) || defined (_DEBUG) || defined (RETAILLOG)
if (! p)
IFDBG(DebugOut (DEBUG_ERROR, L"Shell: Link not found for cid 0x%04x\n", cid));
#endif
return p;
}
static void L2CAP_BufferFree (BD_BUFFER *pBuf) {
if (! pBuf->fMustCopy)
g_funcFree (pBuf, g_pvFreeData);
}
static BD_BUFFER *L2CAP_BufferAlloc (int cSize) {
SVSUTIL_ASSERT (cSize > 0);
BD_BUFFER *pRes = (BD_BUFFER *)g_funcAlloc (cSize + sizeof (BD_BUFFER), g_pvAllocData);
pRes->cSize = cSize;
pRes->cEnd = pRes->cSize;
pRes->cStart = 0;
pRes->fMustCopy = FALSE;
pRes->pFree = L2CAP_BufferFree;
pRes->pBuffer = (unsigned char *)(pRes + 1);
return pRes;
}
static BD_BUFFER *L2CAP_BufferCopy (BD_BUFFER *pBuffer) {
BD_BUFFER *pRes = L2CAP_BufferAlloc (pBuffer->cSize);
pRes->cSize = pBuffer->cSize;
pRes->cStart = pBuffer->cStart;
pRes->cEnd = pBuffer->cEnd;
pRes->fMustCopy = FALSE;
pRes->pFree = L2CAP_BufferFree;
pRes->pBuffer = (unsigned char *)(pRes + 1);
memcpy (pRes->pBuffer, pBuffer->pBuffer, pRes->cSize);
return pRes;
}
static DWORD WINAPI StackDown (LPVOID lpVoid) { // Attention - must increment ref count before calling this!
if (! gpState)
return ERROR_SERVICE_NOT_ACTIVE;
gpState->Lock ();
gpState->DelRef ();
if ((! gpState->fIsRunning) || (! gpState->fConnected)) {
gpState->Unlock ();
return ERROR_SERVICE_NOT_ACTIVE;
}
gpState->fConnected = FALSE;
Link *pLink = gpState->pLinks;
while (gpState->pLinks)
DeleteLink (gpState->pLinks);
SCall *pC = gpState->pCalls;
while (pC) {
if (pC->fWhat != CALL_L2CAP_ACCEPT) {
if (pC->fAutoClean) {
DeleteCall (pC);
pC = gpState->pCalls;
continue;
} else if (! pC->fComplete) {
pC->pLink = NULL;
pC->fComplete = TRUE;
pC->iResult = ERROR_CONNECTION_UNAVAIL;
SetEvent (pC->hEvent);
} else {
pC->pLink = NULL;
if (pC->iResult == ERROR_SUCCESS)
pC->iResult = ERROR_CONNECTION_UNAVAIL;
}
}
pC = pC->pNext;
}
gpState->Unlock ();
return ERROR_SUCCESS;
}
static DWORD WINAPI StackUp (LPVOID lpVoid) { // Attention - must increment ref count before calling this!
if (! gpState)
return ERROR_SERVICE_NOT_ACTIVE;
gpState->Lock ();
gpState->DelRef ();
if ((! gpState->fIsRunning) || gpState->fConnected) {
gpState->Unlock ();
return ERROR_SERVICE_NOT_ACTIVE;
}
gpState->fConnected = TRUE;
gpState->Unlock ();
return ERROR_SUCCESS;
}
static void ProcessExited (HANDLE hProc) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"Shell: ProcessExited 0x%08x\n", hProc));
if (! gpState)
return;
gpState->Lock ();
if (! gpState->fIsRunning) {
gpState->Unlock ();
return;
}
Port *pPort = gpState->pPorts;
while (pPort) {
if (pPort->hProcOwner == hProc) {
unsigned short psm = pPort->psm;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -