NTSTATUS BthEchoCliRetrieveServerBthAddress( __in PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx ) /*++ Description: Retrieve server Bth address Arguments: DevCtx - Client context where we store bth address Return Value: NTSTATUS Status code. --*/ { NTSTATUS status, statusReuse; WDF_MEMORY_DESCRIPTOR outMemDesc; WDF_REQUEST_REUSE_PARAMS ReuseParams; BTH_DEVICE_INFO serverDeviceInfo; WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); statusReuse = WdfRequestReuse(DevCtx->Header.Request, &ReuseParams); ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); RtlZeroMemory( &serverDeviceInfo, sizeof(serverDeviceInfo) ); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &outMemDesc, &serverDeviceInfo, sizeof(serverDeviceInfo) ); status = WdfIoTargetSendInternalIoctlSynchronously( DevCtx->Header.IoTarget, DevCtx->Header.Request, IOCTL_INTERNAL_BTHENUM_GET_DEVINFO, NULL, //inMemDesc &outMemDesc, NULL, //sendOptions NULL //bytesReturned ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Failed to obtain server device info, Status code %!STATUS!\n", status); goto exit; } DevCtx->ServerBthAddress = serverDeviceInfo.address; exit: return status; }
NTSTATUS BthEchoCliRetrieveServerSdpRecord( __in PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx, __out PBTH_SDP_STREAM_RESPONSE * ServerSdpRecord ) /*++ Description: Retrive server SDP record. We call this function on every file open to get the PSM Arguments: DevCtx - Client context ServerSdpRecord - SDP record retrieved Return Value: NTSTATUS Status code. --*/ { NTSTATUS status, statusReuse, disconnectStatus; WDF_MEMORY_DESCRIPTOR inMemDesc; WDF_MEMORY_DESCRIPTOR outMemDesc; WDF_REQUEST_REUSE_PARAMS ReuseParams; BTH_SDP_CONNECT connect = {0}; BTH_SDP_DISCONNECT disconnect = {0}; BTH_SDP_SERVICE_ATTRIBUTE_SEARCH_REQUEST requestSdp = {0}; BTH_SDP_STREAM_RESPONSE responseSdp = {0}; ULONG requestSize; PBTH_SDP_STREAM_RESPONSE serverSdpRecord = NULL; WDFREQUEST request; WDF_OBJECT_ATTRIBUTES attributes; PAGED_CODE(); // // Allocate the request we will use for obtaining sdp record // NOTE that we do it for every file open, hence we // // can't use reserve request from the context // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); status = WdfRequestCreate( &attributes, DevCtx->Header.IoTarget, &request ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Failed to allocate request for retriving server sdp record, Status code %!STATUS!\n", status); goto exit; } connect.bthAddress = DevCtx->ServerBthAddress; connect.requestTimeout = SDP_REQUEST_TO_DEFAULT; connect.fSdpConnect = 0; // // Connect to the SDP service. // WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &inMemDesc, &connect, sizeof(connect) ); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &outMemDesc, &connect, sizeof(connect) ); status = WdfIoTargetSendIoctlSynchronously( DevCtx->Header.IoTarget, request, IOCTL_BTH_SDP_CONNECT, &inMemDesc, &outMemDesc, NULL, //sendOptions NULL //bytesReturned ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "IOCTL_BTH_SDP_CONNECT failed, Status code %!STATUS!\n", status); goto exit1; } // // Obtain the required size of the SDP record // requestSdp.hConnection = connect.hConnection; requestSdp.uuids[0].u.uuid128 = BTHECHOSAMPLE_SVC_GUID; requestSdp.uuids[0].uuidType = SDP_ST_UUID128; requestSdp.range[0].minAttribute = 0; requestSdp.range[0].maxAttribute = 0xFFFF; WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); statusReuse = WdfRequestReuse(request, &ReuseParams); ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &inMemDesc, &requestSdp, sizeof(requestSdp) ); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &outMemDesc, &responseSdp, sizeof(responseSdp) ); status = WdfIoTargetSendIoctlSynchronously( DevCtx->Header.IoTarget, request, IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH, &inMemDesc, &outMemDesc, NULL, //sendOptions NULL //bytesReturned ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, "IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH failed while querying response size, " "status code %!STATUS!\n", status); goto exit2; } // // Allocate the required size for SDP record // status = RtlULongAdd( responseSdp.requiredSize, sizeof(BTH_SDP_STREAM_RESPONSE), &requestSize ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, "SDP record size too large, status code %!STATUS!\n", status); goto exit2; } serverSdpRecord = ExAllocatePoolWithTag(NonPagedPool, requestSize, POOLTAG_BTHECHOSAMPLE); if (NULL == serverSdpRecord) { status = STATUS_INSUFFICIENT_RESOURCES; TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, "Allocating SDP record failed, returning status code %!STATUS!\n", status); goto exit2; } // // Send request with required size // WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); statusReuse = WdfRequestReuse(request, &ReuseParams); ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &inMemDesc, &requestSdp, sizeof(requestSdp) ); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &outMemDesc, serverSdpRecord, requestSize ); status = WdfIoTargetSendIoctlSynchronously( DevCtx->Header.IoTarget, request, IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH, &inMemDesc, &outMemDesc, NULL, //sendOptions NULL //bytesReturned ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, "IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH failed, status code %!STATUS!\n", status); ExFreePoolWithTag(serverSdpRecord, POOLTAG_BTHECHOSAMPLE); } else { *ServerSdpRecord = serverSdpRecord; } exit2: // // Disconnect from SDP service. // WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); statusReuse = WdfRequestReuse(request, &ReuseParams); ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); disconnect.hConnection = connect.hConnection; WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &inMemDesc, &disconnect, sizeof(disconnect) ); disconnectStatus = WdfIoTargetSendIoctlSynchronously( DevCtx->Header.IoTarget, request, IOCTL_BTH_SDP_DISCONNECT, &inMemDesc, NULL, //outMemDesc NULL, //sendOptions NULL //bytesReturned ); ASSERT(NT_SUCCESS(disconnectStatus)); //Disconnect should not fail if (!NT_SUCCESS(disconnectStatus)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "IOCTL_BTH_SDP_DISCONNECT failed, Status code %!STATUS!\n", status); } exit1: WdfObjectDelete(request); exit: return status; }
VOID Toastmon_WriteRequestCompletionRoutine( IN WDFREQUEST Request, IN WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, IN WDFCONTEXT Context ) /*++ Routine Description: Completion Routine Arguments: CompletionParams - Contains the results of the transfer such as IoStatus, Length, Buffer, etc. Context - context value specified in the WdfRequestSetCompletionRoutine Return Value: VOID --*/ { WDF_REQUEST_REUSE_PARAMS params; PTARGET_DEVICE_INFO targetInfo; NTSTATUS status; UNREFERENCED_PARAMETER(Context); targetInfo = GetTargetDeviceInfo(Target); // // Delete the memory object because we create a new one every time we post // the request. For perf reason, it would be better to preallocate even memory object. // Also for driver created requests, do not call WdfRequestRetrieve functions to get // the buffers. WdfRequestRetrieveBuffer functions can be called only for requests // delivered by the queue. // WdfObjectDelete(CompletionParams->Parameters.Write.Buffer); // // Scrub the request for reuse. // WDF_REQUEST_REUSE_PARAMS_INIT(¶ms, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_SUCCESS); status = WdfRequestReuse(Request, ¶ms); ASSERT(NT_SUCCESS(status)); // // RequestReuse zero all the values in structure pointed by CompletionParams. // So you must get all the information from completion params before // calling RequestReuse. // targetInfo->WriteRequest = Request; // // Don't repost the request in the completion routine because it may lead to recursion // if the driver below completes the request synchronously. // return; }
NTSTATUS PowerContextReuseRequest( _In_ PCDROM_DEVICE_EXTENSION DeviceExtension ) /*++ Routine Description: reset fields for the request. Arguments: DeviceExtension - device context Return Value: NTSTATUS --*/ { NTSTATUS status = STATUS_SUCCESS; WDF_REQUEST_REUSE_PARAMS reuseParams; PIRP irp = NULL; RtlZeroMemory(&(DeviceExtension->PowerContext.SenseData), sizeof(DeviceExtension->PowerContext.SenseData)); RtlZeroMemory(&(DeviceExtension->PowerContext.Srb), sizeof(DeviceExtension->PowerContext.Srb)); irp = WdfRequestWdmGetIrp(DeviceExtension->PowerContext.PowerRequest); // Re-use the previously created PowerRequest object and format it WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); status = WdfRequestReuse(DeviceExtension->PowerContext.PowerRequest, &reuseParams); if (NT_SUCCESS(status)) { // This request was preformated during initialization so this call should never fail. status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget, DeviceExtension->PowerContext.PowerRequest, IOCTL_SCSI_EXECUTE_IN, NULL, NULL, NULL, NULL, NULL, NULL); if (!NT_SUCCESS(status)) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "PowerContextReuseRequest: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n", status)); } } // Do some basic initialization of the PowerRequest, the rest will be done by the caller // of this function if (NT_SUCCESS(status)) { PIO_STACK_LOCATION nextStack = NULL; nextStack = IoGetNextIrpStackLocation(irp); nextStack->MajorFunction = IRP_MJ_SCSI; nextStack->Parameters.Scsi.Srb = &(DeviceExtension->PowerContext.Srb); DeviceExtension->PowerContext.Srb.Length = sizeof(SCSI_REQUEST_BLOCK); DeviceExtension->PowerContext.Srb.OriginalRequest = irp; DeviceExtension->PowerContext.Srb.SenseInfoBuffer = &(DeviceExtension->PowerContext.SenseData); DeviceExtension->PowerContext.Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE; } return status; }
NTSTATUS FORCEINLINE BthEchoSharedSendBrbSynchronously( _In_ WDFIOTARGET IoTarget, _In_ WDFREQUEST Request, _In_ PBRB Brb, _In_ ULONG BrbSize ) /*++ Routine Description: This routine formats a request with brb and sends it synchronously Arguments: IoTarget - Target to send the brb to Request - request object to be formatted with brb Brb - Brb to be sent BrbSize - size of the Brb data structure Return Value: NTSTATUS Status code. Notes: This routine does calls WdfRequestReuse on the Request passed in. Caller need not do so before passing in the request. This routine does not complete the request in case of failure. Caller must complete the request in case of failure. --*/ { NTSTATUS status; WDF_REQUEST_REUSE_PARAMS reuseParams; WDF_MEMORY_DESCRIPTOR OtherArg1Desc; WDF_REQUEST_REUSE_PARAMS_INIT( &reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED ); status = WdfRequestReuse(Request, &reuseParams); if (!NT_SUCCESS(status)) { goto exit; } WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( &OtherArg1Desc, Brb, BrbSize ); status = WdfIoTargetSendInternalIoctlOthersSynchronously( IoTarget, Request, IOCTL_INTERNAL_BTH_SUBMIT_BRB, &OtherArg1Desc, NULL, //OtherArg2 NULL, //OtherArg4 NULL, //RequestOptions NULL //BytesReturned ); exit: return status; }
NTSTATUS BthEchoRepeatReaderSubmit( _In_ PBTHECHOSAMPLE_DEVICE_CONTEXT_HEADER DevCtxHdr, _In_ PBTHECHO_REPEAT_READER RepeatReader ) /*++ Description: This routine submits the repeat reader. In case of failure it invoked contreader failed callback Arguments: DevCtxHdr - Device context header RepeatReader - Repeat reader to submit Return Value: NTSTATUS Status code. --*/ { NTSTATUS status, statusReuse; WDF_REQUEST_REUSE_PARAMS reuseParams; struct _BRB_L2CA_ACL_TRANSFER *brb = &RepeatReader->TransferBrb; DevCtxHdr->ProfileDrvInterface.BthReuseBrb((PBRB)brb, BRB_L2CA_ACL_TRANSFER); WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_UNSUCCESSFUL); statusReuse = WdfRequestReuse(RepeatReader->RequestPendingRead, &reuseParams); NT_ASSERT(NT_SUCCESS(statusReuse)); UNREFERENCED_PARAMETER(statusReuse); // // Check if we are stopping, if yes set StopEvent and exit. // // After this point request is eligible for cancellation, so if this // flag gets set after we check it, request will be cancelled for stopping // the repeat reader and next time around we will stop when we are invoked // again upon completion of cancelled request. // if (RepeatReader->Stopping) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONT_READER, "Continuos reader 0x%p stopping", RepeatReader); KeSetEvent(&RepeatReader->StopEvent, 0, FALSE); status = STATUS_SUCCESS; goto exit; } // // Format request for L2CA IN transfer // status = BthEchoConnectionObjectFormatRequestForL2CaTransfer( RepeatReader->Connection, RepeatReader->RequestPendingRead, &brb, RepeatReader->MemoryPendingRead, ACL_TRANSFER_DIRECTION_IN | ACL_SHORT_TRANSFER_OK ); if (!NT_SUCCESS(status)) { goto exit; } // // Set a CompletionRoutine callback function. // WdfRequestSetCompletionRoutine( RepeatReader->RequestPendingRead, BthEchoRepeatReaderPendingReadCompletion, RepeatReader ); // // Clear the stop event before sending the request // This is relevant only on start of the repeat reader // (i.e. the first submission) // this event eventually gets set only when repeat reader stops // and not on every resubmission. // KeClearEvent(&RepeatReader->StopEvent); if (FALSE == WdfRequestSend( RepeatReader->RequestPendingRead, DevCtxHdr->IoTarget, NULL )) { status = WdfRequestGetStatus(RepeatReader->RequestPendingRead); TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n", RepeatReader->RequestPendingRead, brb, status ); goto exit; } else { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONT_READER, "Resubmited pending read with request 0x%p, Brb 0x%p", RepeatReader->RequestPendingRead, brb ); } exit: if (!NT_SUCCESS(status)) { // // Invoke the reader failed callback before setting the event // to ensure that the connection object is alive during this callback // RepeatReader->Connection->ContinuousReader.BthEchoConnectionObjectContReaderFailedCallback( RepeatReader->Connection->DevCtxHdr, RepeatReader->Connection ); // // If we failed to send pending read, set the event since // we will not get completion callback // KeSetEvent(&RepeatReader->StopEvent, 0, FALSE); } return status; }