📄 sdpdb.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:
SdpDB.CPP
Abstract:
This module implemnts BTh SDP core spec.
Doron J. Holan
Notes:
Environment:
Kernel mode only
Revision History:
*/
#include "common.h"
#if defined (UNDER_CE)
#include <bt_os.h>
#endif
///////////////////////////////////////////////////////////////////////////
// INTERNAL Defines
///////////////////////////////////////////////////////////////////////////
const ULONG SdpDatabase::SDP_TAG = 'CpdS';
const ULONG PM_TAG = 'xMtP';
const ULONG RV_TAG = 'VceR';
#if SDP_VERBOSE
ULONG SDP_DBG_FLAGS = DEFAULT_SDP_DBG_FLAGS;
#endif // SDP_VERBOSE
//
// Service record stream whose form is (Attrib ID, AttibValue)
// SDP_ATTRIB_RECORD_HANDLE
// UINT32 0x0
//
// SDP_ATTRIB_CLASS_ID_LIST,
// SEQ
// UUID16 ServiceDiscoveryServerServiceClassID_UUID16
//
// SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST
// SEQ
// SEQ
// UUID16 L2CAP_PROTOCOL_UUID16
// UINT 16 0x00001
// SEQ
// UUID16 SDP_PROTOCOL_UUID16
//
// (SDP_ATTRIB_BROWSE_GROUP_LIST has been removed for WinCE)
// SDP_ATTRIB_BROWSE_GROUP_LIST
// SEQ
// UUID16 PublicBrowseGroupServiceClassID_UUID16
//
// SDP_ATTRIB_LANG_BASE_ATTIB_ID_LIST
// SEQ
// UINT16 0x656e (language, english "en")
// UINT16 0x0061 (encoding, utf-8)
// UINT16 0x0100 (offset)
//
// 0x100 + STRING_NAME_OFFSET
// STRING "Service Discovery"
//
// 0x100 + STRING_DESCRIPTION_OFFSET
// STRING "Publishes services to remote devices"
//
// 0x100 + STIRNG_PROVIDER_NAME_OFFSET
// STRING "Microsoft"
//
// SDP_ATTRIB_PRIV_VERSION_NUMBER_LIST
// SEQ
// UINT16 0x0100
//
// SDP_ATTRIB_SDP_DATABASE_STATE
// UINT32 0x00 (this is only an initial value and changes every time a
// record is added or removed)
//
#if defined (UNDER_CE)
// WinCE doesn't include SDP_ATTRIB_BROWSE_GROUP_LIST or PublicBrowseGroupServiceClassID_UUID16.
const UCHAR g_ServiceStream[] = {
0x35, 0x90, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
0x01, 0x35, 0x03, 0x19, 0x10, 0x00, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35,
0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x00, 0x01,
0x09, 0x00, 0x06, 0x35,
0x09, 0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01, 0x00, 0x09, 0x01,
0x00, 0x25, 0x12, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x44,
0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x00, 0x09, 0x01, 0x01,
0x25, 0x25, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x73, 0x20,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20,
0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x73, 0x00, 0x09, 0x01, 0x02, 0x25, 0x0a, 0x4d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x00, 0x09, 0x02, 0x00, 0x35, 0x03, 0x09,
0x01, 0x00, 0x09, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00,
};
#else
const UCHAR g_ServiceStream[] = {
0x35, 0x98, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
0x01, 0x35, 0x03, 0x19, 0x10, 0x00, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35,
0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x00, 0x01,
0x09, 0x00, 0x05, 0x35, 0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x06, 0x35,
0x09, 0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01, 0x00, 0x09, 0x01,
0x00, 0x25, 0x12, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x44,
0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x00, 0x09, 0x01, 0x01,
0x25, 0x25, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x73, 0x20,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20,
0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x73, 0x00, 0x09, 0x01, 0x02, 0x25, 0x0a, 0x4d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x00, 0x09, 0x02, 0x00, 0x35, 0x03, 0x09,
0x01, 0x00, 0x09, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00,
};
#endif // UNDER_CE
ULONG g_ServiceStreamSize = sizeof(g_ServiceStream)/sizeof(g_ServiceStream[0]);
#define INVALID_RECORD_HANDLE 1
#define INVALID_ID ((PVOID) 1)
#define INIT_HANDLE_VALUE 0xFFFF
SdpDatabase::ServiceRecord::ServiceRecord() : handle(INVALID_ID), streamSize(0),
pStream(NULL), recordHandle(INVALID_RECORD_HANDLE)
{
InitializeListHead(&link);
RtlZeroMemory(&psmList, sizeof(psmList));
#if defined (UNDER_CE)
hCallerProc = GetCallerProcess();
#endif
}
SdpDatabase::ServiceRecord::~ServiceRecord()
{
if (pStream) {
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
delete[] pStream;
#else
SdpFreePool(pStream);
#endif
}
pStream = NULL;
}
SdpDatabase::ServiceRecord * SdpDatabase::GetServiceRecord(HANDLE handle)
{
ServiceRecord *pRecord;
// PLIST_ENTRY entry;
for (pRecord = m_ServiceRecordList.GetHead();
pRecord != NULL;
pRecord = m_ServiceRecordList.GetNext(pRecord)) {
if (pRecord->handle == handle) {
return pRecord;
}
}
return NULL;
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
SdpDatabase::RecordValidator::RecordValidator(PBTHDDI_SDP_VALIDATE_INTERFACE pValInterface)
{
flags = pValInterface->Flags;
pValidator = pValInterface->Validator;
pRemoteValidator = pValInterface->RemoteValidator;
pUpdateValidator = pValInterface->UpdateValidator;
pContext = pValInterface->ValidatorContext;
pValInterface->Cookie = (PVOID) this;
InitializeListHead(&link);
}
#endif // UNDER_CE
SdpDatabase::ProtMux::ProtMux(GUID *prot) : protocol(*prot)
{
InitializeListHead(&link);
}
SdpDatabase::SdpDatabase() : m_nextRecordHandle(INIT_HANDLE_VALUE)
{
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
KeInitializeSemaphore(&m_dbStateSemaphore, 1, 1);
#else
#define INITIAL_DB_STATE 0
m_dbState = INITIAL_DB_STATE;
#endif
}
SdpDatabase::~SdpDatabase()
{
while (!m_ServiceRecordList.IsEmpty()) {
ServiceRecord *pRecord = m_ServiceRecordList.RemoveHead();
delete pRecord;
}
while (!m_ProtMuxList.IsEmpty()) {
ProtMux *ppm = m_ProtMuxList.RemoveHead();
delete ppm;
}
}
NTSTATUS SdpDatabase::Init()
{
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
NTSTATUS status;
#endif
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
m_pSdpRecord = new (NonPagedPool, SDP_TAG) ServiceRecord;
#else
m_pSdpRecord = new ServiceRecord;
#endif
if (m_pSdpRecord == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
m_pSdpRecord->pStream = new (NonPagedPool, SDP_TAG) UCHAR[g_ServiceStreamSize];
#else
m_pSdpRecord->pStream = (UCHAR*) SdpAllocatePool(g_ServiceStreamSize * sizeof(UCHAR));
m_pSdpRecord->handle = 0;
#endif
if (m_pSdpRecord->pStream == NULL) {
delete m_pSdpRecord;
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(&m_pSdpRecord->serviceClass,
&ServiceDiscoveryServerServiceClassID_UUID,
sizeof(GUID));
m_pSdpRecord->psmList.count = 1;
m_pSdpRecord->psmList.list[0].psm = PSM_SDP;
RtlCopyMemory(&m_pSdpRecord->psmList.list[0].protocol,
&SDP_PROTOCOL_UUID,
sizeof(GUID));
m_pSdpRecord->streamSize = g_ServiceStreamSize;
RtlCopyMemory(m_pSdpRecord->pStream, g_ServiceStream, g_ServiceStreamSize);
m_pSdpRecord->recordHandle = 0x0;
m_ServiceRecordList.AddHead(m_pSdpRecord);
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
//
// Add the service to the security database, we do not want to prompt the
// user when a remote device connects
//
status = Globals.pSecDB->AddService(ServiceDiscoveryServerServiceClassID_UUID,
SERVICE_SECURITY_NONE);
#endif // UNDER_CE
AddProtMux((LPGUID) &RFCOMM_PROTOCOL_UUID);
return STATUS_SUCCESS;
}
NTSTATUS SdpDatabase::ValidateStream(UCHAR *pStream, ULONG streamSize, PULONG_PTR err)
{
return ::ValidateStream(pStream, streamSize, NULL, NULL, err);
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
NTSTATUS
SdpDatabase::ValidateRecordExternal(
PUCHAR pStream,
ULONG streamSize,
PSDP_TREE_ROOT_NODE pTreeRoot,
PPSM_LIST pPsmList,
ULONG flags,
GUID* pServiceClassUuid
)
{
NTSTATUS status = STATUS_SUCCESS;
m_RecordValidatorList.Lock();
RecordValidator *prv;
RECORD_VALIDATOR_INFO rvi;
RtlZeroMemory(&rvi, sizeof(rvi));
rvi.pPsmList = pPsmList;
RtlCopyMemory(&rvi.serviceClass, pServiceClassUuid, sizeof(GUID));
for (prv = m_RecordValidatorList.GetHead();
prv != NULL;
prv = m_RecordValidatorList.GetNext(prv)) {
if (prv->flags & RVFI_STREAM) {
rvi.pStream = pStream;
rvi.streamSize = streamSize;
}
else {
rvi.pStream = NULL;
rvi.streamSize = 0;
}
if (prv->flags & RVFI_TREE) {
rvi.pTreeRoot = pTreeRoot;
}
else {
rvi.pTreeRoot = NULL;
}
status = prv->pValidator(prv->pContext,
&rvi,
flags);
if (!NT_SUCCESS(status)) {
break;
}
}
m_RecordValidatorList.Unlock();
return status;
}
#endif // UNDER_CE
#define SERVICE_SECURITY_ENCRYPT_BOTH (SERVICE_SECURITY_ENCRYPT_REQUIRED | SERVICE_SECURITY_ENCRYPT_OPTIONAL)
#define SERVICE_SECURITY_AUTH_TYPES (SERVICE_SECURITY_NONE | SERVICE_SECURITY_AUTHORIZE | SERVICE_SECURITY_AUTHENTICATE)
// NTSTATUS SdpDatabase::AddRecord(PIRP pIrp, PHANDLE pHandle, ULONG *pfService)
NTSTATUS SdpDatabase::AddRecord(PUCHAR pStream, ULONG streamSize, PHANDLE pHandle, ServiceRecord *pRecordOriginal) // UNDER_CE
{
NTSTATUS status;
PUCHAR pNewStream = NULL;
ULONG newStreamSize = 0;
ServiceRecord* pRecord = NULL;
ULONG count, size;
PSDP_NODE pCont = NULL;
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
BOOLEAN protIsMux;
stack = IoGetCurrentIrpStackLocation(pIrp);
inLen = stack->Parameters.DeviceIoControl.InputBufferLength;
if (stack->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_BTH_SDP_SUBMIT_RECORD_WITH_INFO) {
BthSdpRecord* pBthSdpRecord;
if (inLen < sizeof(BthSdpRecord)) {
return STATUS_INVALID_BUFFER_SIZE;
}
pBthSdpRecord = (BthSdpRecord *) pIrp->AssociatedIrp.SystemBuffer;
pStream = pBthSdpRecord->record;
streamSize = pBthSdpRecord->recordLength;
//
// Validity check for all IN params
//
// Make sure only the supported flags are being sent
//
if ((pBthSdpRecord->fCodService & ~COD_SERVICE_VALID_MASK) != 0 ||
(pBthSdpRecord->fSecurity & ~SERVICE_SECURITY_VALID_MASK) != 0 ||
(pBthSdpRecord->fOptions & ~SERVICE_OPTION_VALID_MASK) != 0) {
return STATUS_INVALID_PARAMETER;
}
fSecurity = pBthSdpRecord->fSecurity;
//
// Only bthport controls the limited discovery bit
//
if (fSecurity & COD_SERVICE_LIMITED) {
_DbgPrintF(DBG_SDP_ERROR,
("clients are not allowed to set limited COD service"));
return STATUS_INVALID_PARAMETER;
}
//
// Make sure exclusive flags are not being sent together
//
if ((fSecurity & SERVICE_SECURITY_ENCRYPT_BOTH) ==
SERVICE_SECURITY_ENCRYPT_BOTH) {
_DbgPrintF(
DBG_SDP_ERROR,
("encryption can only be required or optional, not both!"));
return STATUS_INVALID_PARAMETER;
}
//
// To have an encrypted channel, you must be authenticated first
//
if ((fSecurity & SERVICE_SECURITY_ENCRYPT_BOTH) != 0 &&
(fSecurity & SERVICE_SECURITY_AUTHENTICATE) == 0) {
_DbgPrintF(DBG_SDP_ERROR, ("encryption requires authentication"));
return STATUS_INVALID_PARAMETER;
}
//
// Check to see that only one of the AUTH security flags is set. If more
// than one flag is set, then subtracting one will not create the logical
// and inverse of itself. For instance:
// 0x101 & (0x101-1) == 0x100 ... invalid
// 0x100 & (0x100-1) == 0x000 ... valid
//
if (((fSecurity & SERVICE_SECURITY_AUTH_TYPES) &
((fSecurity & SERVICE_SECURITY_AUTH_TYPES) - 1)) != 0) {
_DbgPrintF(DBG_SDP_ERROR,
("more than one authentication type was specified"));
return STATUS_INVALID_PARAMETER;
}
//
// Make sure the size reported in the structure is the size of the
// stream buffer
//
if (inLen - (sizeof(BthSdpRecord) - sizeof(pBthSdpRecord->record)) !=
streamSize) {
_DbgPrintF(
DBG_SDP_ERROR,
("BthSdpRecord::recordLength (%d) does not match buffer"
" size (%d)", streamSize,
inLen - (sizeof(BthSdpRecord) - sizeof(pBthSdpRecord->record))
));
return STATUS_INVALID_PARAMETER;
}
fService = pBthSdpRecord->fCodService;
fOptions = pBthSdpRecord->fOptions;
if (fOptions & SERVICE_OPTION_PERMANENT) {
_DbgPrintF(DBG_SDP_ALL,
("%c%cpermanent records are not yet supported!", 7, 7));
}
}
else {
pStream = (UCHAR *) pIrp->AssociatedIrp.SystemBuffer;
streamSize = inLen;
fSecurity = SERVICE_SECURITY_USE_DEFAULTS;
fService = 0;
fOptions = 0;
}
#endif
//
// Make sure it is well formed (ie a sequence of ushort (attrib id) + one
// element (attrib value)
//
status = SdpIsStreamRecord(pStream, streamSize);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Make sure all of the universal attributes have the correct syntax and
// that all of the attributes we require locally are present
//
USHORT err = 0xFFFF;
status = SdpVerifyServiceRecord(pStream,
streamSize,
VERIFY_CHECK_MANDATORY_LOCAL,
&err);
if (!NT_SUCCESS(status)) {
return status;
}
PSDP_NODE tree = NULL;
PSDP_NODE uint32;
PVOID pv = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -