📄 btsdpcon.cpp
字号:
//
// 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.
//
/*++
Module Name:
BTSDP.CPP
Abstract:
This module implemnts BTh SDP core spec.
Doron Holan
Notes:
Environment:
Kernel mode only
Revision History:
*/
#include "common.h"
#include "sdplib.h"
#define SDPI_TAG 'IpdS'
extern SdpDatabase *pSdpDB;
#define SDPC_TAG 'CpdS'
#define SDP_DEFAULT_TIMEOUT 30 // in seconds
#define SDP_SCAN_INTERVAL 1
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
LIST_ENTRY SdpConnection::_TimeoutListHead;
KSPIN_LOCK SdpConnection::_TimeoutListLock;
KTIMER SdpConnection::_TimeoutTimer;
KDPC SdpConnection::_TimeoutTimerDpc;
#endif
#if UPF
USHORT GetMaxByteCount(USHORT inMtu)
{
HANDLE hKey;
USHORT rVal = 0;
if (NT_SUCCESS(BthPort_OpenKey(NULL,
STR_REG_MACHINE STR_SOFTWARE_KEYW,
&hKey))) {
ULONG tmp = 0;
if (NT_SUCCESS(QueryKeyValue(hKey,
L"OverrideMaxByteCount",
&tmp,
sizeof(ULONG))) && tmp != 0) {
rVal = (USHORT) tmp;
}
ZwClose(hKey);
}
if (rVal == 0) {
//
// Compute max byte count by taking the maximum buffer the server can send me
// and taking out all the fixed fields
//
rVal = (USHORT) inMtu -
(sizeof(SdpPDU) +
sizeof(USHORT) + // AttribyteListsByteCount
sizeof(UCHAR)); // cont state of zero
}
else {
SdpPrint(0, ("***UPF*** overrding max byte count with %d\n", (ULONG) rVal));
}
return rVal;
}
#else
//
// USHORT = AttribyteListsByteCount
// UCHAR = cont state of zero
//
#define GetMaxByteCount(mbc) ((USHORT) (mbc) - (sizeof(SdpPDU) + sizeof(USHORT) + sizeof(UCHAR)))
#endif // UPF
NTSTATUS
SendBrbCompletion(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
#if SDP_VERBOSE
NTSTATUS TestWalkStream(PVOID Context, UCHAR DataType, ULONG DataSize, PUCHAR Stream);
#endif
// On WinCE we malloc blocks of these structs at a time, so the constructor is never called.
SdpConnection::SdpConnection(BThDevice *pDev, BOOLEAN isClient)
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
: fileObjectList(), clientQueue(), channelState(SdpChannelStateClosed),
pDevice(pDev), client(isClient)
#endif
{
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
ZERO_THIS();
_DbgPrintF(DBG_SDP_TRACE, ("SdpConnection created 0x%x", this));
InitializeListHead(&entry);
KeInitializeSpinLock(&stateSpinLock);
IoInitializeRemoveLock(&remLock, 0, 0, 0);
clientQueue.SetQueueCancelRoutine(_QueueCancelRoutine, this);
Acquire(REASON(AcquireCreate));
#endif // UNDER_CE
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
void
SdpConnection::ReleaseAndProcessNextRequest(
PIRP pIrp
)
{
PIRP pNextRequest = NULL;
clientQueue.RemoveIfAvailable(&pNextRequest);
//
// pNextRequest already has a reference taken out on this connection, so
// this object is still valid if there is another request
//
Release(pIrp);
if (pNextRequest) {
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pNextRequest);
switch (stack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_BTH_SDP_SERVICE_SEARCH:
SendServiceSearchRequest(pIrp);
break;
case IOCTL_BTH_SDP_ATTRIBUTE_SEARCH:
SendAttributeSearchRequest(pIrp);
break;
case IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH:
SendServiceSearchAttributeRequest(pIrp);
break;
default:
ASSERT(FALSE);
}
}
}
void SdpConnection::ReleaseAndWait()
{
IoReleaseRemoveLockAndWait(&remLock, REASON(AcquireCreate));
}
#endif
SdpConnection::~SdpConnection()
{
SdpPrint(SDP_DBG_CON_TRACE, ("SdpConnection destroyed %p\n", this));
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
CompletePendingConnectRequests(STATUS_UNSUCCESSFUL);
if (pReadBuffer) {
ExFreePool(pReadBuffer);
pReadBuffer = NULL;
}
if (pReadIrp) {
IoFreeIrp(pReadIrp);
pReadIrp = NULL;
}
if (pWriteIrp) {
IoFreeIrp(pWriteIrp);
pWriteIrp = NULL;
}
if (pReadBrb) {
delete pReadBrb;
pReadBrb = NULL;
}
#endif
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
BOOLEAN SdpConnection::Init()
{
pReadIrp = IoAllocateIrp(pDevice->m_Struct.FunctionalDeviceObject->StackSize+1, FALSE);
pWriteIrp = IoAllocateIrp(pDevice->m_Struct.FunctionalDeviceObject->StackSize+1, FALSE);
pReadBrb = new (NonPagedPool, SDPC_TAG) BRB;
return (pReadIrp != NULL) && (pWriteIrp != NULL);
}
void
SdpConnection::FireWmiEvent(
SDP_SERVER_LOG_TYPE Type,
PVOID Buffer,
ULONG Length
)
{
#ifdef SDP_LOGGING
PSDP_SERVER_LOG_INFO pLog;
ULONG size = sizeof(*pLog) + Length -1;
pLog = (PSDP_SERVER_LOG_INFO)
ExAllocatePoolWithTag(PagedPool, size, SDPC_TAG);
if (pLog) {
RtlZeroMemory(pLog, size);
pLog->type = Type;
pLog->info.btAddress = btAddress;
pLog->mtu = outMtu;
pLog->dataLength = Length;
RtlCopyMemory(pLog->data, Buffer, Length);
WmiFireEvent(pDevice->m_Struct.FunctionalDeviceObject,
(LPGUID) &GUID_BTHPORT_WMI_SDP_SERVER_LOG_INFO,
0,
size,
pLog);
}
#endif // SDP_LOGGING
}
void
SdpConnection::FireWmiEvent(
SDP_SERVER_LOG_TYPE Type,
const bt_addr& Address,
USHORT Mtu
)
{
#ifdef SDP_LOGGING
PSDP_SERVER_LOG_INFO pLog;
pLog = (PSDP_SERVER_LOG_INFO)
ExAllocatePoolWithTag(PagedPool, sizeof(*pLog), SDPI_TAG);
if (pLog) {
RtlZeroMemory(pLog, sizeof(*pLog));
pLog->type = Type;
pLog->info.btAddress = Address;
pLog->mtu = Mtu;
pLog->dataLength = 0;
WmiFireEvent(pDevice->m_Struct.FunctionalDeviceObject,
(LPGUID) &GUID_BTHPORT_WMI_SDP_SERVER_LOG_INFO,
0,
sizeof(*pLog),
pLog);
}
#endif SDP_LOGGING
}
BOOLEAN
SdpConnection::AddFileObject(PFILE_OBJECT pFileObject)
{
FileObjectEntry *pEntry = new(PagedPool, SDPC_TAG) FileObjectEntry(pFileObject);
if (pEntry == NULL) {
return FALSE;
}
ASSERT(closing == FALSE);
_DbgPrintF(DBG_SDP_INFO, ("Adding file object %p\n", pEntry));
fileObjectList.AddTail(pEntry);
InterlockedIncrement(&createCount);
ASSERT(createCount > 0);
return TRUE;
}
LONG
SdpConnection::RemoveFileObject(PFILE_OBJECT pFileObject)
{
FileObjectEntry *pEntry = FindFileObject(pFileObject);
if (pEntry == NULL) {
//
// Somebody send a disconnect for a connection they did not own
//
return -1;
}
return RemoveFileObject(pEntry);
}
LONG
SdpConnection::RemoveFileObject(FileObjectEntry *pEntry)
{
ULONG c;
ASSERT(closing == FALSE);
_DbgPrintF(DBG_SDP_INFO, ("Removing file object %p\n", pEntry));
fileObjectList.RemoveAt(pEntry);
delete pEntry;
c = InterlockedDecrement(&createCount);
if (c == 0) {
_DbgPrintF(DBG_SDP_INFO, ("Closing on %p is TRUE\n", this));
closing = TRUE;
ASSERT(fileObjectList.IsEmpty());
}
return c;
}
FileObjectEntry *
SdpConnection::FindFileObject(
PFILE_OBJECT pFileObject
)
{
FileObjectEntry *pEntry;
for (pEntry = fileObjectList.GetHead();
pEntry != NULL;
pEntry = fileObjectList.GetNext(pEntry)) {
if (pEntry->pFileObject == pFileObject) {
return pEntry;
}
}
return NULL;
}
void
SdpConnection::Cleanup(
PFILE_OBJECT pFileObject
)
{
PIRP irp;
CIRP_LIST list;
clientQueue.Cleanup(&list, pFileObject);
while (!list.IsEmpty()) {
irp = list.RemoveHead();
Release(irp);
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
}
BOOLEAN
SdpConnection::SetupReadBuffer()
{
pReadBuffer = ExAllocatePoolWithTag(NonPagedPool, inMtu, SDPC_TAG);
return pReadBuffer != NULL;
}
BOOLEAN
SdpConnection::InMtuDone(
USHORT mtu
)
{
KIRQL irql;
BOOLEAN resp = FALSE;
LockState(&irql);
SdpPrint(SDP_DBG_CONFIG_INFO, ("InMtuDone, %d\n", mtu));
inMtu = mtu;
configInDone = TRUE;
if (configOutDone) {
SdpPrint(SDP_DBG_CONFIG_INFO, ("all done!\n"));
channelState = SdpChannelStateOpen;
configInDone = configOutDone = FALSE;
resp = TRUE;
}
else {
SdpPrint(SDP_DBG_CONFIG_INFO, ("waiting for out!\n"));
}
UnlockState(irql);
return resp;
}
BOOLEAN
SdpConnection::OutMtuDone(
USHORT mtu
)
{
KIRQL irql;
BOOLEAN resp = FALSE;
LockState(&irql);
SdpPrint(SDP_DBG_CONFIG_INFO, ("OutMtuDone, %d\n", mtu));
if (mtu == 0) {
mtu = L2CAP_DEFAULT_MTU;
SdpPrint(SDP_DBG_CONFIG_INFO, ("Converting 0 to default mtu (%d)\n", (ULONG) mtu));
}
outMtu = mtu;
configOutDone = TRUE;
if (configInDone) {
SdpPrint(SDP_DBG_CONFIG_INFO, ("all done!\n"));
channelState = SdpChannelStateOpen;
configInDone = configOutDone = FALSE;
resp = TRUE;
}
else {
SdpPrint(SDP_DBG_CONFIG_INFO, ("waiting for in!\n"));
}
UnlockState(irql);
return resp;
}
BOOLEAN SdpConnection::FinalizeConnection()
{
NTSTATUS status;
BOOLEAN disconnect = FALSE;
if (SetupReadBuffer() == FALSE) {
SdpPrint(SDP_DBG_CONFIG_ERROR | SDP_DBG_CONFIG_WARNING,
("FinalizeConnection, config done, no buffers!\n"));
disconnect = TRUE;
}
else if (IsClient()) {
SdpPrint(SDP_DBG_CONFIG_INFO,
("FinalizeConnection, completing all pended connect requests\n"));
CompletePendingConnectRequests(STATUS_SUCCESS);
}
else {
//
// We are the server in this connection, send down a read to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -