📄 btsdp.cpp
字号:
return STATUS_INVALID_BUFFER_SIZE;
}
if (stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BthSdpStreamResponse)) {
return STATUS_INVALID_BUFFER_SIZE;
}
pSearch = (BthSdpServiceAttributeSearchRequest *) pIrp->AssociatedIrp.SystemBuffer;
status = VerifyServiceSearch(pSearch->uuids, &maxUuids);
if (!NT_SUCCESS(status)) {
return status;
}
status =
VerifyAttributeSearch(pSearch->range,
&maxRange,
stack->Parameters.DeviceIoControl.InputBufferLength -
(sizeof(*pSearch) - sizeof(pSearch->range))
);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Check to see if this is a local search
//
if (pSearch->hConnection == HANDLE_SDP_LOCAL) {
ULONG size;
UCHAR *pResult;
status = Globals.pSdpDB->ServiceSearchAttributeResponseLocal(
pSearch->uuids,
maxUuids,
pSearch->range,
maxRange,
&pResult,
&size);
if (NT_SUCCESS(status)) {
BthSdpStreamResponse *pResponse = (BthSdpStreamResponse *)
pIrp->AssociatedIrp.SystemBuffer;
ULONG responseSize;
responseSize =
stack->Parameters.DeviceIoControl.OutputBufferLength -
(sizeof(*pResponse) - sizeof(pResponse->response));
pResponse->requiredSize = size;
if (responseSize < size) {
info = responseSize;
}
else {
info = size;
}
pResponse->responseSize = info;
RtlCopyMemory(pResponse->response, pResult, info);
info += (sizeof(*pResponse) - sizeof(pResponse->response));
ExFreePool(pResult);
}
return status;
}
pCon = NULL;
status = AcquireConnection(pSearch->hConnection, &pCon, pIrp);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Set the max range and uuids before we enqueue the request because the
// send function assumes it is set (even for a queud irp processed at a
// later time)
//
SetMaxUuidsInIrp(pIrp, maxUuids);
SetMaxRangeInIrp(pIrp, maxRange);
BOOLEAN added = pCon->clientQueue.AddIfBusy(pIrp, &status);
if (added) {
//
// The queue is busy and the request has been queued. Don't touch the
// irp anymore
//
return STATUS_PENDING;
}
else if (!NT_SUCCESS(status)) {
//
// The request was cancelled or something went wrong. The irp was not
// enqueued. Return the error status
//
pCon->ReleaseAndProcessNextRequest(pIrp);
return status;
}
else {
//
// This is the current request on the connection, see if it matches the
// previous request
//
//
// While we do not cache ServiceSearch responses, this will clean up
// any cached responsed from previous queries
//
status = pCon->IsPreviousRequest(pIrp,
SdpPDU_ServiceSearchAttributeRequest,
pSearch->uuids,
pSearch->range,
maxRange,
&info);
if (NT_SUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL) {
pCon->ReleaseAndProcessNextRequest(pIrp);
return STATUS_SUCCESS;
}
}
//
// The actual transmission over the wire
//
return pCon->SendServiceSearchAttributeRequest(pIrp);
#endif // UNDER_CE
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
NTSTATUS SdpInterface::Disconnect(PIRP pIrp, ULONG_PTR& info)
{
SdpConnection *pCon;
NTSTATUS status;
PVOID hConnection;
LONG count = -1;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
info = 0;
if (stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(HANDLE)) {
return STATUS_BUFFER_TOO_SMALL;
}
hConnection = *(HANDLE*) pIrp->AssociatedIrp.SystemBuffer;
m_SdpConnectionList.Lock();
pCon = FindConnection(hConnection);
if (pCon) {
if (pCon->IsClient()) {
//
// This will mark the connection as closing which will protect this
// object from further connections until we remove it from the linked
// list
//
count = pCon->RemoveFileObject(stack->FileObject);
}
else {
//
// We found a connection, but it is a server connection. Spec says
// that a server should not allow a disconnect except for extreme
// conditions.
//
pCon = NULL;
}
}
m_SdpConnectionList.Unlock();
if (pCon) {
if (count == -1) {
//
// Somehow the caller got the hConnection, but never called connect
//
status = STATUS_INVALID_PARAMETER;
}
else {
//
// count == 0, the object is going away
//
status = STATUS_SUCCESS;
}
}
else {
status = STATUS_DEVICE_NOT_CONNECTED;
}
if (NT_SUCCESS(status)) {
pCon->Cleanup(stack->FileObject);
if (count > 0) {
//
// There are still other clients using the underlying bth connection
//
return status;
}
BRB brb;
RtlZeroMemory(&brb, sizeof(brb));
brb.BrbHeader.Length = sizeof (_BRB_L2CA_DISCONNECT_REQ);
brb.BrbHeader.Type = BRB_L2CA_DISCONNECT_REQ;
brb.BrbHeader.Status = STATUS_SUCCESS;
brb.BrbL2caDisconnectReq.hConnection = hConnection;
//
// Removed from the list in final cleanup
//
// m_SdpConnectionList.Lock();
// m_SdpConnectionList.RemoveAt(pCon);
// m_SdpConnectionList.Unlock();
//
// pCon will be deleted in the IndicationFinalCleanup handler
//
status = SendBrb(&brb);
}
return status;
}
void
SdpInterface::CloseConnections(
PIRP pIrp
)
{
PFILE_OBJECT pFileObject = IoGetCurrentIrpStackLocation(pIrp)->FileObject;
m_SdpConnectionList.Lock();
m_SdpConnectionList.Unlock();
}
#endif // UNDER_CE
NTSTATUS
CrackContState(
IN OUT PUCHAR &pStream,
IN OUT ULONG &streamSize,
OUT ContinuationState *pContState,
OUT PSDP_ERROR pSdpError
)
{
// PAGED_CODE();
BOOLEAN res = pContState->Read(pStream, streamSize);
if (res == FALSE) {
//
// spec says, max cont state is 16 bytes long. We get the streamSize
// from the pdu parameter length field so this is actually an error in
// that field, not an error in the continuation state.
//
*pSdpError = SDP_ERROR_INVALID_PDU_SIZE;
return STATUS_INVALID_PARAMETER;
}
//
// one for the header + actual state info
//
pStream += (1 + pContState->size);
streamSize -= (1 + pContState->size);
ASSERT(streamSize == 0);
return STATUS_SUCCESS;
}
NTSTATUS
CrackSequenceParameter(
IN OUT PUCHAR &pStream,
IN OUT ULONG &streamSize,
IN ULONG minRemainingStream,
OUT ULONG *pSequenceSize
)
{
// PAGED_CODE();
UCHAR type, sizeIndex;
SdpRetrieveHeader(pStream, type, sizeIndex);
if (type != (UCHAR) SDP_TYPE_SEQUENCE) {
return STATUS_INVALID_PARAMETER;
}
if (sizeIndex < 5 || sizeIndex > 7) {
return STATUS_INVALID_PARAMETER;
}
pStream++;
streamSize--;
ULONG elementSize, storageSize;
SdpRetrieveVariableSize(pStream, sizeIndex, &elementSize, &storageSize);
if (elementSize + storageSize >= streamSize + minRemainingStream) {
return STATUS_INVALID_PARAMETER;
}
*pSequenceSize = 1 + storageSize + elementSize;
//
// We have incremented past the header above, so decrement back
//
NTSTATUS status = ValidateStream(pStream-1,
*pSequenceSize,
NULL,
NULL,
NULL);
if (!NT_SUCCESS(status)) {
return status;
}
pStream += (storageSize + elementSize);
streamSize -= (storageSize + elementSize);
return STATUS_SUCCESS;
}
NTSTATUS
SdpInterface::CrackClientServiceSearchRequest(
IN UCHAR *pServiceSearchRequestStream,
IN ULONG streamSize,
OUT UCHAR **ppSequenceStream,
OUT ULONG *pSequenceStreamSize,
OUT USHORT *pMaxRecordCount,
OUT ContinuationState *pContState,
OUT PSDP_ERROR pSdpError
)
{
// PAGED_CODE();
UCHAR *pStream;
//
// data elem sequence = 2 = 1 (seq hdr) + 1 (seq size)
// = 3 = 1 (elem hdr) + 2 (size of uuid16)
// sizeof(max record count) = 2
// cont state >= 1
//
if (streamSize < 8) {
*pSdpError = MapNtStatusToSdpError(STATUS_INVALID_PARAMETER);
return STATUS_INVALID_PARAMETER;
}
pStream = pServiceSearchRequestStream;
//
// 3 = sizeof(max record count) + at least one for cont state
//
NTSTATUS status;
*ppSequenceStream = pStream;
status =
CrackSequenceParameter(pStream, streamSize, 3, pSequenceStreamSize);
if (!NT_SUCCESS(status)) {
*pSdpError = MapNtStatusToSdpError(STATUS_INVALID_PARAMETER);
return STATUS_INVALID_PARAMETER;
}
RtlRetrieveUshort(pMaxRecordCount, pStream);
*pMaxRecordCount = RtlUshortByteSwap(*pMaxRecordCount);
pStream += sizeof(USHORT);
streamSize -= sizeof(USHORT);
return CrackContState(pStream, streamSize, pContState, pSdpError);
}
NTSTATUS
SdpInterface::CrackClientServiceAttributeRequest(
IN UCHAR *pServiceAttributeRequestStream,
IN ULONG streamSize,
OUT ULONG *pRecordHandle,
OUT USHORT *pMaxAttribByteCount,
OUT UCHAR **ppAttribIdListStream,
OUT ULONG *pAttribIdListStreamSize,
OUT ContinuationState *pContState,
OUT PSDP_ERROR pSdpError
)
{
// PAGED_CODE();
//
// record handle = 4
// max attrib byte count = 2
// id list (seq) = 2 = 1 (seq header) + 1 (stream size)
// = 3 = 1 (elem hdr) + 2 (size of ushort)
// cont state = 1
//
if (streamSize < 12) {
*pSdpError = MapNtStatusToSdpError(STATUS_INVALID_PARAMETER);
return STATUS_INVALID_PARAMETER;
}
UCHAR *pStream;
pStream = pServiceAttributeRequestStream;
RtlRetrieveUlong(pRecordHandle, pStream);
*pRecordHandle = RtlUlongByteSwap(*pRecordHandle);
pStream += sizeof(ULONG);
streamSize -= sizeof(ULONG);
RtlRetrieveUshort(pMaxAttribByteCount, pStream);
*pMaxAttribByteCount = RtlUshortByteSwap(*pMaxAttribByteCount);
pStream += sizeof(USHORT);
streamSize -= sizeof(USHORT);
//
// 1 = cont state
//
NTSTATUS status;
*ppAttribIdListStream = pStream;
status =
CrackSequenceParameter(pStream, streamSize, 1, pAttribIdListStreamSize);
if (!NT_SUCCESS(status)) {
*pSdpError = MapNtStatusToSdpError(STATUS_INVALID_PARAMETER);
return STATUS_INVALID_PARAMETER;
}
return CrackContState(pStream, streamSize, pContState, pSdpError);
}
NTSTATUS
SdpInterface::CrackClientServiceSearchAttributeRequest(
IN UCHAR *pServiceSearchAttributeRequestStream,
IN ULONG streamSize,
OUT UCHAR **ppServiceSearchSequence,
OUT ULONG *pServiceSearchSequenceSize,
OUT USHORT *pMaxAttributeByteCount,
OUT UCHAR **ppAttributeIdSequence,
OUT ULONG *pAttributeIdSequenceSize,
OUT ContinuationState *pContState,
OUT PSDP_ERROR pSdpError
)
{
// PAGED_CODE();
//
// uuid elem sequence = 2 = 1 (seq hdr) + 1 (seq size)
// = 3 = 1 (elem hdr) + 2 (size of uuid16)
// max attrib byte count = 2
// attrib elem sequence = 2 = 1 (seq hdr) + 1 (seq size)
// = 3 = 1 (elem hdr) + 2 (size of uuid16)
// cont state = 1
//
if (streamSize < 13) {
*pSdpError = MapNtStatusToSdpError(STATUS_INVALID_PARAMETER);
return STATUS_INVALID_PARAMETER;
}
NTSTATUS status;
UCHAR *pStream;
pStream = pServiceSearchAttributeRequestStream;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -