summaryrefslogtreecommitdiff
path: root/bluetooth/bthecho/bthcli/sys
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-04-29 09:48:49 -0700
committerDave Wilson <[email protected]>2015-04-29 10:47:29 -0700
commitd40232638faaab19de557e70a3ee938da7a35295 (patch)
tree14e61c973745949af186b7940e3a53d25322f5de /bluetooth/bthecho/bthcli/sys
parent02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff)
samples update for //build
Diffstat (limited to 'bluetooth/bthecho/bthcli/sys')
-rw-r--r--bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx101
-rw-r--r--bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj201
-rw-r--r--bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters43
-rw-r--r--bluetooth/bthecho/bthcli/sys/client.c1207
-rw-r--r--bluetooth/bthecho/bthcli/sys/client.h58
-rw-r--r--bluetooth/bthecho/bthcli/sys/device.c458
-rw-r--r--bluetooth/bthecho/bthcli/sys/device.h91
-rw-r--r--bluetooth/bthecho/bthcli/sys/driver.c210
-rw-r--r--bluetooth/bthecho/bthcli/sys/driver.h34
-rw-r--r--bluetooth/bthecho/bthcli/sys/queue.c349
-rw-r--r--bluetooth/bthecho/bthcli/sys/queue.h31
11 files changed, 2783 insertions, 0 deletions
diff --git a/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx
new file mode 100644
index 00000000..9f55cc59
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx
@@ -0,0 +1,101 @@
+;/*++
+;
+;Copyright (c) 1990-2000 Microsoft Corporation
+;
+; 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.
+;
+;Module Name:
+; BthEchoSampleCli.inx
+;
+;Abstract:
+; INF file for installing the Bluetooth Echo Sample Client
+;
+; devcon.exe BthEchoSampleCli.inf BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4}
+;
+;--*/
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=Sample
+ClassGuid={e0cbf06c-cd8b-4647-bb8a-263b43f0f974}
+Provider=%MSFTSAMPLE%
+DriverVer=06/21/2006,6.0.5841.
+CatalogFile=KmdfSamples.cat
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+[SourceDisksNames]
+1 = %DiskId1%,,,""
+
+[SourceDisksFiles]
+BthEchoSampleCli.sys = 1,,
+
+;*****************************************
+; BthEchoSampleCli Install Section
+;*****************************************
+
+[Manufacturer]
+%MSFTSAMPLE%=Microsoft,NTamd64...1
+%MSFTSAMPLE%=Microsoft,NTx86...1
+
+[Microsoft.NTamd64...1]
+%BthEchoSampleCli.DeviceDesc% = BthEchoSampleCli_Inst,BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4}
+
+[Microsoft.NTx86...1]
+%BthEchoSampleCli.DeviceDesc% = BthEchoSampleCli_Inst,BTHENUM\{c07508f2-b970-43ca-b5dd-cc4f2391bef4}
+[BthEchoSampleCli_Inst.NT]
+CopyFiles=Drivers_Dir
+
+[Drivers_Dir]
+BthEchoSampleCli.sys
+
+
+;-------------- Service installation
+[BthEchoSampleCli_Inst.NT.Services]
+AddService = BthEchoSampleCli,%SPSVCINST_ASSOCSERVICE%, BthEchoSampleCli_Service_Inst
+
+; -------------- BthEchoSampleCli driver install sections
+[BthEchoSampleCli_Service_Inst]
+DisplayName = %BthEchoSampleCli.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\BthEchoSampleCli.sys
+
+;
+;--- BthEchoSampleCli_Inst Coinstaller installation ------
+;
+
+[DestinationDirs]
+BthEchoSampleCli_Inst_CoInstaller_CopyFiles = 11
+
+[BthEchoSampleCli_Inst.NT.CoInstallers]
+AddReg=BthEchoSampleCli_Inst_CoInstaller_AddReg
+CopyFiles=BthEchoSampleCli_Inst_CoInstaller_CopyFiles
+
+[BthEchoSampleCli_Inst_CoInstaller_AddReg]
+HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
+
+[BthEchoSampleCli_Inst_CoInstaller_CopyFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
+
+[SourceDisksFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
+
+[BthEchoSampleCli_Inst.NT.Wdf]
+KmdfService = BthEchoSampleCli, BthEchoSampleCli_Inst_wdfsect
+[BthEchoSampleCli_Inst_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+
+[Strings]
+SPSVCINST_ASSOCSERVICE= 0x00000002
+MSFTSAMPLE = "Microsoft Sample"
+StdMfg = "(Standard system devices)"
+DiskId1 = "BthEchoSampleCli installation disk"
+BthEchoSampleCli.DeviceDesc = "Bluetooth Echo Sample Client"
+BthEchoSampleCli.SVCDESC = "BthEchoSampleCli"
diff --git a/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj
new file mode 100644
index 00000000..f30cb9f3
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{AADDAE40-9C46-4C50-AC5F-FF957C3A6E94}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{FA5BA6C8-691B-4FF7-9AFB-B50CE61C8ED1}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="driver.c; device.c; client.c; queue.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ </ClCompile>
+ <Inf Include=".\BthEchoSampleCli.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\BthEchoSampleCli.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>BthEchoSampleCli</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>BthEchoSampleCli</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>BthEchoSampleCli</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>BthEchoSampleCli</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\..\common\lib\$(IntDir)\bthecho.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters
new file mode 100644
index 00000000..176a771f
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{12E8E936-7BEE-4822-9BB5-A95B2C6C6537}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{379796ED-172B-4B2C-9E23-302F90088C9F}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{5B69AC41-D941-4D63-82AB-FAED650522CE}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{1907D7F9-002C-43DE-BB60-1544D4D62A74}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="client.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="device.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="driver.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="queue.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\BthEchoSampleCli.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include=".\BthEchoSampleCli.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/bluetooth/bthecho/bthcli/sys/client.c b/bluetooth/bthecho/bthcli/sys/client.c
new file mode 100644
index 00000000..a3947b2a
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/client.c
@@ -0,0 +1,1207 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ 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.
+
+Module Name:
+
+ client.c
+
+Abstract:
+
+ Contains Bluetooth client functionality.
+
+Environment:
+
+ Kernel mode only
+
+
+--*/
+
+#include "clisrv.h"
+#include "device.h"
+#include "client.h"
+
+#define INITGUID
+#include "public.h"
+
+#if defined(EVENT_TRACING)
+#include "client.tmh"
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, BthEchoCliBthQueryInterfaces)
+#pragma alloc_text (PAGE, BthEchoCliRetrieveServerSdpRecord)
+#endif
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+BthEchoCliBthQueryInterfaces(
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx
+ )
+/*++
+
+Description:
+
+ Query profile driver interface
+
+Arguments:
+
+ DevCtx - Client context where we store the interface
+
+Return Value:
+
+ NTSTATUS Status code.
+
+--*/
+{
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ status = WdfFdoQueryForInterface(
+ DevCtx->Header.Device,
+ &GUID_BTHDDI_PROFILE_DRIVER_INTERFACE,
+ (PINTERFACE) (&DevCtx->Header.ProfileDrvInterface),
+ sizeof(DevCtx->Header.ProfileDrvInterface),
+ BTHDDI_PROFILE_DRIVER_INTERFACE_VERSION_FOR_QI,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "QueryInterface failed for Interface profile driver interface, version %d, Status code %!STATUS!\n",
+ BTHDDI_PROFILE_DRIVER_INTERFACE_VERSION_FOR_QI,
+ status);
+
+ goto exit;
+ }
+
+exit:
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+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);
+ NT_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;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+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);
+ NT_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(NonPagedPoolNx, 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);
+ NT_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);
+ NT_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
+ );
+
+ NT_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;
+}
+
+NTSTATUS
+BthEchoCliRetrievePsmFromSdpRecord(
+ _In_ PBTHDDI_SDP_PARSE_INTERFACE SdpParseInterface,
+ _In_ PBTH_SDP_STREAM_RESPONSE ServerSdpRecord,
+ _Out_ USHORT * Psm
+ )
+/*++
+
+Description:
+
+ Retrieve PSM from the SDP record
+
+Arguments:
+
+ sdpParseInterface - Parse interface used for sdp parse functions
+ ServerSdpRecord - SDP record to obtain Psm from
+ Psm - Psm retrieved
+
+Return Value:
+
+ NTSTATUS Status code.
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PUCHAR nextElement;
+ ULONG nextElementSize;
+
+ PSDP_TREE_ROOT_NODE sdpTree = NULL;
+ PSDP_NODE nodeProtoDescList = NULL;
+ PSDP_NODE nodeProto0 = NULL;
+ PSDP_NODE nodeProto0UUID = NULL;
+ PSDP_NODE nodeProto0SParam0 = NULL;
+
+ SdpParseInterface->SdpGetNextElement(
+ &(ServerSdpRecord->response[0]),
+ ServerSdpRecord->responseSize,
+ NULL,
+ &nextElement,
+ &nextElementSize
+ );
+
+ if(nextElementSize == 0)
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP,
+ "Getting first element from SDP record failed, returning status code %!STATUS!\n", status);
+ goto exit;
+ }
+
+ status = SdpParseInterface->SdpConvertStreamToTree(
+ nextElement,
+ nextElementSize,
+ &sdpTree,
+ POOLTAG_BTHECHOSAMPLE
+ );
+
+ if(!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP,
+ "Converting SDP record to tree failed, status code %!STATUS!\n", status);
+ goto exit;
+ }
+
+ //
+ //Find PROTOCOL_DESCRIPTOR_LIST in the tree
+ //
+ status = SdpParseInterface->SdpFindAttributeInTree(
+ sdpTree,
+ (USHORT)SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST,
+ &nodeProtoDescList
+ );
+
+ if(!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP,
+ "FindAttribute failed for SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, status code %!STATUS!\n", status);
+ goto exit0;
+ }
+
+ if(nodeProtoDescList->hdr.Type != SDP_TYPE_SEQUENCE)
+ {
+ goto SdpFormatError;
+ }
+
+ //
+ // Get the next sequence.
+ //
+
+ if(nodeProtoDescList->u.sequence.Link.Flink == NULL)
+ {
+ goto SdpFormatError;
+ }
+
+ nodeProto0 = CONTAINING_RECORD(nodeProtoDescList->u.sequence.Link.Flink, SDP_NODE, hdr.Link);
+
+ if(nodeProto0->hdr.Type != SDP_TYPE_SEQUENCE)
+ {
+ goto SdpFormatError;
+ }
+
+ if(nodeProto0->u.sequence.Link.Flink == NULL)
+ {
+ goto SdpFormatError;
+ }
+
+ //
+ // Get the first GUID, (L2CAP)
+ //
+
+ nodeProto0UUID = CONTAINING_RECORD(nodeProto0->u.sequence.Link.Flink, SDP_NODE, hdr.Link);
+
+ if(nodeProto0UUID->hdr.Type != SDP_TYPE_UUID)
+ {
+ goto SdpFormatError;
+ }
+
+ if(nodeProto0UUID->hdr.Link.Flink == NULL)
+ {
+ goto SdpFormatError;
+ }
+
+ //
+ // Get the PSM
+ //
+
+ nodeProto0SParam0 = CONTAINING_RECORD(nodeProto0UUID->hdr.Link.Flink, SDP_NODE, hdr.Link);
+ if(nodeProto0SParam0->hdr.SpecificType != SDP_ST_UINT16)
+ {
+ goto SdpFormatError;
+ }
+
+ *Psm = nodeProto0SParam0->u.uint16;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_SDP,
+ "Psm: %d", *Psm);
+
+ goto exit0;
+
+SdpFormatError:
+
+ status = STATUS_DEVICE_DATA_ERROR;
+
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP,
+ "Parsing error due to invalid SDP record, returning status code %!STATUS!\n", status);
+
+exit0:
+
+ SdpParseInterface->SdpFreeTree(sdpTree);
+
+exit:
+ return status;
+}
+
+
+EVT_WDF_REQUEST_COMPLETION_ROUTINE
+BthEchoCliRemoteConnectCompletion;
+
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+BthEchoCliIndicationCallback(
+ _In_ PVOID Context,
+ _In_ INDICATION_CODE Indication,
+ _In_ PINDICATION_PARAMETERS_ENHANCED Parameters
+ )
+/*++
+
+Description:
+
+ Indication callback passed to bth stack while sending open channel BRB
+ Bth stack sends notification related to the connection.
+
+Arguments:
+
+ Context - We receive data connection as the context
+ Indication - Type of indication
+ Parameters - Parameters of indication
+
+--*/
+{
+ PBTHECHO_CONNECTION connection = (PBTHECHO_CONNECTION) Context;
+
+ UNREFERENCED_PARAMETER(Parameters);
+
+ //
+ // Only supporting connect and disconnect
+ //
+
+ switch(Indication)
+ {
+ //
+ // We don't add/release reference to anything because our connection
+ // is scoped within file object lifetime
+ //
+ case IndicationAddReference:
+ case IndicationReleaseReference:
+ break;
+ case IndicationRemoteConnect:
+ {
+ //
+ // We don't expect connection
+ //
+ NT_ASSERT(FALSE);
+ break;
+ }
+ case IndicationRemoteDisconnect:
+ {
+ //
+ // This is an indication that server has disconnected
+ // In response we disconnect from our end
+ //
+
+ BthEchoConnectionObjectRemoteDisconnect(
+ connection->DevCtxHdr,
+ connection
+ );
+
+ break;
+ }
+ case IndicationRemoteConfigRequest:
+ case IndicationRemoteConfigResponse:
+ case IndicationFreeExtraOptions:
+ break;
+ }
+}
+
+
+VOID
+BthEchoCliRemoteConnectCompletion(
+ _In_ WDFREQUEST Request,
+ _In_ WDFIOTARGET Target,
+ _In_ PWDF_REQUEST_COMPLETION_PARAMS Params,
+ _In_ WDFCONTEXT Context
+ )
+
+/*++
+Description:
+
+ Completion routine for Create request which we format as open
+ channel BRB and send down the stack. We complete the Create request
+ in this routine.
+
+ We receive open channel BRB as the context. This BRB
+ is part of the request context and doesn't need to be freed
+ explicitly.
+
+ Connection is part of the context in the BRB.
+
+Arguments:
+
+ Request - Create request that we formatted with open channel BRB
+ Target - Target to which we sent the request
+ Params - Completion params
+ Context - We receive BRB as the context
+
+Return Value:
+
+ NTSTATUS Status code.
+--*/
+
+{
+ NTSTATUS status;
+ struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *brb;
+ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx;
+ PBTHECHO_CONNECTION connection;
+
+ DevCtx = GetClientDeviceContext(WdfIoTargetGetDevice(Target));
+
+ status = Params->IoStatus.Status;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT,
+ "Connection completion, status: %!STATUS!", status);
+
+ brb = (struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *) Context;
+
+ connection = (PBTHECHO_CONNECTION) brb->Hdr.ClientContext[0];
+
+ //
+ // In the client we don't check for ConnectionStateDisconnecting state
+ // because only file close generates disconnect which
+ // cannot happen before create completes. And we complete Create
+ // only after we process this completion.
+ //
+
+ if(NT_SUCCESS(status))
+ {
+ connection->OutMTU = brb->OutResults.Params.Mtu;
+ connection->InMTU = brb->InResults.Params.Mtu;
+ connection->ChannelHandle = brb->ChannelHandle;
+ connection->RemoteAddress = brb->BtAddress;
+
+ connection->ConnectionState = ConnectionStateConnected;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT,
+ "Connection (0x%x) established to server", brb->OutResults.Params.RetransmissionAndFlow.Mode);
+
+ //
+ // Call the function in device.c (BthEchoCliConnectionStateConnected)
+ // for any post processing after connection has been established
+ //
+ status = BthEchoCliConnectionStateConnected(WdfRequestGetFileObject(Request), connection);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // If such post processing fails we disconnect
+ //
+ BthEchoConnectionObjectRemoteDisconnect(
+ &(DevCtx->Header),
+ connection
+ );
+ }
+ }
+ else
+ {
+ connection->ConnectionState = ConnectionStateConnectFailed;
+ }
+
+ //
+ // Complete the Create request
+ //
+ WdfRequestComplete(Request, status);
+
+ return;
+}
+
+
+_IRQL_requires_same_
+NTSTATUS
+BthEchoCliOpenRemoteConnection(
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx,
+ _In_ WDFFILEOBJECT FileObject,
+ _In_ WDFREQUEST Request
+ )
+/*++
+
+Description:
+
+ This routine is invoked by BthEchoCliEvtDeviceFileCreate.
+ In this routine we send down open channel BRB.
+
+ This routine allocates open channel BRB. If the request
+ is sent down successfully completion routine needs to free
+ this BRB.
+
+Arguments:
+
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx -
+ _In_ WDFFILEOBJECT FileObject -
+ _In_ WDFREQUEST Request -
+
+Return Value:
+
+ NTSTATUS Status code.
+
+--*/
+{
+ NTSTATUS status;
+ WDFOBJECT connectionObject;
+ struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *brb = NULL;
+ PBTHECHO_CONNECTION connection = NULL;
+ PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT fileCtx = GetFileContext(FileObject);
+ ULONG modeConfigFlag = CM_BASIC;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT,
+ "Connect request");
+
+ //
+ // Create the connection object that would store information
+ // about the open channel
+ //
+ // Set file object as the parent for this connection object
+ //
+ status = BthEchoConnectionObjectCreate(
+ &DevCtx->Header,
+ FileObject, //parent
+ &connectionObject
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+ connection = GetConnectionObjectContext(connectionObject);
+
+ connection->ConnectionState = ConnectionStateConnecting;
+
+ //
+ // Get the BRB from request context and initialize it as
+ // BRB_L2CA_OPEN_CHANNEL BRB
+ //
+ brb = (struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *)GetRequestContext(Request);
+
+ DevCtx->Header.ProfileDrvInterface.BthReuseBrb(
+ (PBRB)brb,
+ BRB_L2CA_OPEN_ENHANCED_CHANNEL
+ );
+
+ brb->Hdr.ClientContext[0] = connection;
+ brb->BtAddress = DevCtx->ServerBthAddress;
+ brb->Psm = fileCtx->ServerPsm;
+
+ brb->ChannelFlags = CF_ROLE_EITHER;
+
+ brb->ConfigOut.Flags = CFG_ENHANCED;
+ //
+ // Open an ERTM channel if the local host supports it
+ //
+ if (DevCtx->Header.LocalFeatures.Mask & BTH_HOST_FEATURE_ENHANCED_RETRANSMISSION_MODE) {
+ modeConfigFlag |= CM_RETRANSMISSION_AND_FLOW;
+ brb->ConfigOut.ModeConfig.Flags = modeConfigFlag;
+
+ //
+ // Mode is specified using Flags above and this should be 0.
+ //
+ brb->ConfigOut.ModeConfig.RetransmissionAndFlow.Mode = 0;
+ brb->ConfigOut.ModeConfig.RetransmissionAndFlow.MaxTransmit = L2CAP_RAF_DEFAULT_MAXTRANSMIT;
+ brb->ConfigOut.ModeConfig.RetransmissionAndFlow.MaxPDUSize = L2CAP_RAF_DEFAULT_MAX_PDU_SIZE;
+ brb->ConfigOut.ModeConfig.RetransmissionAndFlow.TxWindowSize = L2CAP_RAF_DEFAULT_TX_WINDOW_SIZE;
+ }
+
+ brb->ConfigOut.Flags |= CFG_MTU;
+ brb->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU;
+ brb->ConfigOut.Mtu.Min = L2CAP_MIN_MTU;
+ brb->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU;
+
+ brb->ConfigIn.Flags = CFG_MTU;
+ brb->ConfigIn.Mtu.Max = brb->ConfigOut.Mtu.Max;
+ brb->ConfigIn.Mtu.Min = brb->ConfigOut.Mtu.Min;
+ brb->ConfigIn.Mtu.Preferred = brb->ConfigOut.Mtu.Max;
+
+ //
+ // Get notificaiton about remote disconnect
+ //
+ brb->CallbackFlags = CALLBACK_DISCONNECT;
+
+ brb->Callback = &BthEchoCliIndicationCallback;
+ brb->CallbackContext = connection;
+ brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device);
+ brb->IncomingQueueDepth = 50;
+
+ status = BthEchoSharedSendBrbAsync(
+ DevCtx->Header.IoTarget,
+ Request,
+ (PBRB) brb,
+ sizeof(*brb),
+ BthEchoCliRemoteConnectCompletion,
+ brb //Context
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT,
+ "Sending brb for opening connection failed, returning status code %!STATUS!\n", status);
+
+ goto exit;
+ }
+
+exit:
+
+ if(!NT_SUCCESS(status))
+ {
+ if (connection)
+ {
+ //
+ // Set the right state to facilitate debugging
+ //
+ connection->ConnectionState = ConnectionStateConnectFailed;
+ }
+
+ //
+ // In case of failure of this routine we will fail
+ // Create which will delete file object and since connection object
+ // is child of the file object, it will be deleted too
+ //
+ }
+
+ return status;
+}
+
+
+#else
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+BthEchoCliIndicationCallback(
+ _In_ PVOID Context,
+ _In_ INDICATION_CODE Indication,
+ _In_ PINDICATION_PARAMETERS Parameters
+ )
+/*++
+
+Description:
+
+ Indication callback passed to bth stack while sending open channel BRB
+ Bth stack sends notification related to the connection.
+
+Arguments:
+
+ Context - We receive data connection as the context
+ Indication - Type of indication
+ Parameters - Parameters of indication
+
+--*/
+{
+ PBTHECHO_CONNECTION connection = (PBTHECHO_CONNECTION) Context;
+
+ UNREFERENCED_PARAMETER(Parameters);
+
+ //
+ // Only supporting connect and disconnect
+ //
+
+ switch(Indication)
+ {
+ //
+ // We don't add/release reference to anything because our connection
+ // is scoped within file object lifetime
+ //
+ case IndicationAddReference:
+ case IndicationReleaseReference:
+ break;
+ case IndicationRemoteConnect:
+ {
+ //
+ // We don't expect connection
+ //
+ NT_ASSERT(FALSE);
+ break;
+ }
+ case IndicationRemoteDisconnect:
+ {
+ //
+ // This is an indication that server has disconnected
+ // In response we disconnect from our end
+ //
+
+ BthEchoConnectionObjectRemoteDisconnect(
+ connection->DevCtxHdr,
+ connection
+ );
+
+ break;
+ }
+ case IndicationRemoteConfigRequest:
+ case IndicationRemoteConfigResponse:
+ case IndicationFreeExtraOptions:
+ break;
+ }
+}
+
+VOID
+BthEchoCliRemoteConnectCompletion(
+ _In_ WDFREQUEST Request,
+ _In_ WDFIOTARGET Target,
+ _In_ PWDF_REQUEST_COMPLETION_PARAMS Params,
+ _In_ WDFCONTEXT Context
+ )
+
+/*++
+Description:
+
+ Completion routine for Create request which we format as open
+ channel BRB and send down the stack. We complete the Create request
+ in this routine.
+
+ We receive open channel BRB as the context. This BRB
+ is part of the request context and doesn't need to be freed
+ explicitly.
+
+ Connection is part of the context in the BRB.
+
+Arguments:
+
+ Request - Create request that we formatted with open channel BRB
+ Target - Target to which we sent the request
+ Params - Completion params
+ Context - We receive BRB as the context
+
+Return Value:
+
+ NTSTATUS Status code.
+--*/
+
+{
+ NTSTATUS status;
+ struct _BRB_L2CA_OPEN_CHANNEL *brb;
+ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx;
+ PBTHECHO_CONNECTION connection;
+
+ DevCtx = GetClientDeviceContext(WdfIoTargetGetDevice(Target));
+
+ status = Params->IoStatus.Status;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT,
+ "Connection completion, status: %!STATUS!", status);
+
+ brb = (struct _BRB_L2CA_OPEN_CHANNEL *) Context;
+
+ connection = (PBTHECHO_CONNECTION) brb->Hdr.ClientContext[0];
+
+ //
+ // In the client we don't check for ConnectionStateDisconnecting state
+ // because only file close generates disconnect which
+ // cannot happen before create completes. And we complete Create
+ // only after we process this completion.
+ //
+
+ if(NT_SUCCESS(status))
+ {
+ connection->OutMTU = brb->OutResults.Params.Mtu;
+ connection->InMTU = brb->InResults.Params.Mtu;
+ connection->ChannelHandle = brb->ChannelHandle;
+ connection->RemoteAddress = brb->BtAddress;
+
+ connection->ConnectionState = ConnectionStateConnected;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT,
+ "Connection established to server");
+
+ //
+ // Call the function in device.c (BthEchoCliConnectionStateConnected)
+ // for any post processing after connection has been established
+ //
+ status = BthEchoCliConnectionStateConnected(WdfRequestGetFileObject(Request), connection);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // If such post processing fails we disconnect
+ //
+ BthEchoConnectionObjectRemoteDisconnect(
+ &(DevCtx->Header),
+ connection
+ );
+ }
+ }
+ else
+ {
+ connection->ConnectionState = ConnectionStateConnectFailed;
+ }
+
+ //
+ // Complete the Create request
+ //
+ WdfRequestComplete(Request, status);
+
+ return;
+}
+
+
+
+_IRQL_requires_same_
+NTSTATUS
+BthEchoCliOpenRemoteConnection(
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx,
+ _In_ WDFFILEOBJECT FileObject,
+ _In_ WDFREQUEST Request
+ )
+/*++
+
+Description:
+
+ This routine is invoked by BthEchoCliEvtDeviceFileCreate.
+ In this routine we send down open channel BRB.
+
+ This routine allocates open channel BRB. If the request
+ is sent down successfully completion routine needs to free
+ this BRB.
+
+Arguments:
+
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx -
+ _In_ WDFFILEOBJECT FileObject -
+ _In_ WDFREQUEST Request -
+
+Return Value:
+
+ NTSTATUS Status code.
+
+--*/
+{
+ NTSTATUS status;
+ WDFOBJECT connectionObject;
+ struct _BRB_L2CA_OPEN_CHANNEL *brb = NULL;
+ PBTHECHO_CONNECTION connection = NULL;
+ PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT fileCtx = GetFileContext(FileObject);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT,
+ "Connect request");
+
+ //
+ // Create the connection object that would store information
+ // about the open channel
+ //
+ // Set file object as the parent for this connection object
+ //
+ status = BthEchoConnectionObjectCreate(
+ &DevCtx->Header,
+ FileObject, //parent
+ &connectionObject
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+ connection = GetConnectionObjectContext(connectionObject);
+
+ connection->ConnectionState = ConnectionStateConnecting;
+
+ //
+ // Get the BRB from request context and initialize it as
+ // BRB_L2CA_OPEN_CHANNEL BRB
+ //
+ brb = (struct _BRB_L2CA_OPEN_CHANNEL *)GetRequestContext(Request);
+
+ DevCtx->Header.ProfileDrvInterface.BthReuseBrb(
+ (PBRB)brb,
+ BRB_L2CA_OPEN_CHANNEL
+ );
+
+ brb->Hdr.ClientContext[0] = connection;
+ brb->BtAddress = DevCtx->ServerBthAddress;
+ brb->Psm = fileCtx->ServerPsm;
+
+ brb->ChannelFlags = CF_ROLE_EITHER;
+
+ brb->ConfigOut.Flags = 0;
+ brb->ConfigIn.Flags = 0;
+
+ brb->ConfigOut.Flags |= CFG_MTU;
+ brb->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU;
+ brb->ConfigOut.Mtu.Min = L2CAP_MIN_MTU;
+ brb->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU;
+
+ brb->ConfigIn.Flags = CFG_MTU;
+ brb->ConfigIn.Mtu.Max = brb->ConfigOut.Mtu.Max;
+ brb->ConfigIn.Mtu.Min = brb->ConfigOut.Mtu.Min;
+ brb->ConfigIn.Mtu.Preferred = brb->ConfigOut.Mtu.Max;
+
+ //
+ // Get notificaiton about remote disconnect
+ //
+ brb->CallbackFlags = CALLBACK_DISCONNECT;
+
+ brb->Callback = &BthEchoCliIndicationCallback;
+ brb->CallbackContext = connection;
+ brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device);
+ brb->IncomingQueueDepth = 50;
+
+ status = BthEchoSharedSendBrbAsync(
+ DevCtx->Header.IoTarget,
+ Request,
+ (PBRB) brb,
+ sizeof(*brb),
+ BthEchoCliRemoteConnectCompletion,
+ brb //Context
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT,
+ "Sending brb for opening connection failed, returning status code %!STATUS!\n", status);
+
+ goto exit;
+ }
+
+exit:
+
+ if(!NT_SUCCESS(status))
+ {
+ if (connection)
+ {
+ //
+ // Set the right state to facilitate debugging
+ //
+ connection->ConnectionState = ConnectionStateConnectFailed;
+ }
+
+ //
+ // In case of failure of this routine we will fail
+ // Create which will delete file object and since connection object
+ // is child of the file object, it will be deleted too
+ //
+ }
+
+ return status;
+}
+
+
+#endif
+
diff --git a/bluetooth/bthecho/bthcli/sys/client.h b/bluetooth/bthecho/bthcli/sys/client.h
new file mode 100644
index 00000000..548420aa
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/client.h
@@ -0,0 +1,58 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ 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.
+
+Module Name:
+
+ client.h
+
+Abstract:
+
+ Contains declarations for Bluetooth client functionality.
+
+Environment:
+
+ Kernel mode only
+
+
+--*/
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+BthEchoCliBthQueryInterfaces(
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+BthEchoCliRetrieveServerBthAddress(
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+BthEchoCliRetrieveServerSdpRecord(
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx,
+ _Out_ PBTH_SDP_STREAM_RESPONSE * ServerSdpRecord
+ );
+
+NTSTATUS
+BthEchoCliRetrievePsmFromSdpRecord(
+ _In_ PBTHDDI_SDP_PARSE_INTERFACE sdpParseInterface,
+ _In_ PBTH_SDP_STREAM_RESPONSE ServerSdpRecord,
+ _Out_ USHORT * Psm
+ );
+
+_IRQL_requires_same_
+NTSTATUS
+BthEchoCliOpenRemoteConnection(
+ _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx,
+ _In_ WDFFILEOBJECT FileObject,
+ _In_ WDFREQUEST Request
+ );
+
diff --git a/bluetooth/bthecho/bthcli/sys/device.c b/bluetooth/bthecho/bthcli/sys/device.c
new file mode 100644
index 00000000..177fb823
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/device.c
@@ -0,0 +1,458 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ 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.
+
+Module Name:
+
+ Device.c
+
+Abstract:
+
+ Device and file object related functionality for bthecho client device
+
+Environment:
+
+ Kernel mode only
+
+
+--*/
+
+#include "clisrv.h"
+#include "device.h"
+#include "client.h"
+#include "queue.h"
+
+#define INITGUID
+#include "public.h"
+
+#if defined(EVENT_TRACING)
+#include "device.tmh"
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, BthEchoCliEvtDriverDeviceAdd)
+#pragma alloc_text (PAGE, BthEchoCliEvtDeviceFileCreate)
+#pragma alloc_text (PAGE, BthEchoCliEvtFileClose)
+#endif
+
+NTSTATUS
+BthEchoCliEvtDriverDeviceAdd(
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+)
+/*++
+Routine Description:
+
+ BthEchoCliEvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device. All the software resources
+ should be allocated in this callback.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDF_FILEOBJECT_CONFIG fileobjectConfig;
+ WDF_OBJECT_ATTRIBUTES fileAttributes, requestAttributes;
+ WDF_IO_QUEUE_CONFIG ioQueueConfig;
+ WDFQUEUE queue;
+ PBTHECHOSAMPLE_CLIENT_CONTEXT devCtx;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ //
+ // Configure Pnp/power callbacks
+ //
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = BthEchoCliEvtDeviceSelfManagedIoInit;
+
+ WdfDeviceInitSetPnpPowerEventCallbacks(
+ DeviceInit,
+ &pnpPowerCallbacks
+ );
+
+ //
+ // Configure file callbacks
+ //
+
+ WDF_FILEOBJECT_CONFIG_INIT(
+ &fileobjectConfig,
+ BthEchoCliEvtDeviceFileCreate,
+ BthEchoCliEvtFileClose,
+ WDF_NO_EVENT_CALLBACK // Cleanup
+ );
+
+ //
+ // Inform framework to create context area in every fileobject
+ // so that we can track information per open handle by the
+ // application.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fileAttributes, BTHECHOSAMPLE_CLIENT_FILE_CONTEXT);
+
+ WdfDeviceInitSetFileObjectConfig(
+ DeviceInit,
+ &fileobjectConfig,
+ &fileAttributes
+ );
+
+ //
+ // Inform framework to create context area in every request object.
+ //
+ // We make BRB as the context since we need BRB for all the requests
+ // we handle (Create, Read, Write).
+ //
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
+ &requestAttributes,
+ BRB
+ );
+
+ WdfDeviceInitSetRequestAttributes(
+ DeviceInit,
+ &requestAttributes
+ );
+
+ //
+ // Set device attributes
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, BTHECHOSAMPLE_CLIENT_CONTEXT);
+
+ status = WdfDeviceCreate(
+ &DeviceInit,
+ &deviceAttributes,
+ &device
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "WdfDeviceCreate failed with Status code %!STATUS!\n", status);
+
+ goto exit;
+ }
+
+ devCtx = GetClientDeviceContext(device);
+
+ //
+ // Initialize our context
+ //
+ status = BthEchoCliContextInit(devCtx, device);
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "Initialization of context failed with Status code %!STATUS!\n", status);
+
+ goto exit;
+ }
+
+ status = BthEchoCliBthQueryInterfaces(devCtx);
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+ //
+ // Set up our queue
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &ioQueueConfig,
+ WdfIoQueueDispatchParallel
+ );
+
+ ioQueueConfig.EvtIoRead = BthEchoCliEvtQueueIoRead;
+ ioQueueConfig.EvtIoWrite = BthEchoCliEvtQueueIoWrite;
+ ioQueueConfig.EvtIoStop = BthEchoCliEvtQueueIoStop;
+
+ status = WdfIoQueueCreate(
+ device,
+ &ioQueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &queue
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "WdfIoQueueCreate failed %!STATUS!\n", status);
+ goto exit;
+ }
+
+ //
+ // Enable device interface so that app can open a handle to our device
+ // and talk to it
+ //
+
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ &BTHECHOSAMPLE_DEVICE_INTERFACE,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "Enabling device interface failed with Status code %!STATUS!\n", status);
+
+ goto exit;
+ }
+
+exit:
+ //
+ // We don't need to worry about deleting any objects on failure
+ // because all the object created so far are parented to device and when
+ // we return an error, framework will delete the device and as a
+ // result all the child objects will get deleted along with that.
+ //
+ return status;
+}
+
+NTSTATUS
+BthEchoCliEvtDeviceSelfManagedIoInit(
+ _In_ WDFDEVICE Device
+ )
+/*++
+
+Description:
+
+ This routine is called by the framework only once
+ and hence we use it for our one time initialization.
+
+ Bth addresses for both our local device and server device
+ do not change, hence we retrieve them here.
+
+ Features that the local device supports also do not change,
+ so checking for local L2cap support is done here and saved in the
+ device context header
+
+ Please note that retrieveing server bth address does not
+ require presence of the server. It is remembered from
+ the installation time when the client gets installed for a
+ specific server.
+
+Arguments:
+
+ Device - Framework device object
+
+Return Value:
+
+ NTSTATUS Status code.
+
+--*/
+{
+ NTSTATUS status;
+ PBTHECHOSAMPLE_CLIENT_CONTEXT devCtx = GetClientDeviceContext(Device);
+
+ status = BthEchoSharedRetrieveLocalInfo(&devCtx->Header);
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+ status = BthEchoCliRetrieveServerBthAddress(devCtx);
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+exit:
+ return status;
+}
+
+NTSTATUS
+BthEchoCliConnectionStateConnected(
+ _In_ WDFFILEOBJECT FileObject,
+ _In_ PBTHECHO_CONNECTION Connection
+ )
+/*++
+Description:
+
+ This routine is invoked by BthEchoCliRemoteConnectCompletion
+ function in client.c when opening a remote
+ connection is completed.
+
+ In this routine we set the file context to the connection passed in.
+
+Arguments:
+
+ FileObject - File object whose open resulted in open connection
+ Connection - Our data strucutre to track open connection
+
+Return Value:
+
+ NTSTATUS Status code.
+--*/
+{
+ GetFileContext(FileObject)->Connection = Connection;
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+BthEchoCliEvtDeviceFileCreate(
+ _In_ WDFDEVICE Device,
+ _In_ WDFREQUEST Request,
+ _In_ WDFFILEOBJECT FileObject
+ )
+/*++
+Description:
+
+ This routine is invoked by Framework when an application opens a handle
+ to our device.
+
+ In response we open a remote connection to the server.
+
+Arguments:
+
+ Device - Framework device object
+ Request - Create request
+ FileObject - File object corresponding to Create
+--*/
+{
+ NTSTATUS status;
+ PBTH_SDP_STREAM_RESPONSE serverSdpRecord = NULL;
+ PBTHECHOSAMPLE_CLIENT_CONTEXT devCtx = GetClientDeviceContext(Device);
+ PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT fileCtx = GetFileContext(FileObject);
+ BTHDDI_SDP_PARSE_INTERFACE sdpParseInterface;
+
+ PAGED_CODE();
+
+ //
+ // We need to obtained PSM from the server
+ // For this, first we retrieve the SDP record
+ //
+
+ status = BthEchoCliRetrieveServerSdpRecord(devCtx, &serverSdpRecord);
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+ status = WdfFdoQueryForInterface(
+ Device,
+ &GUID_BTHDDI_SDP_PARSE_INTERFACE,
+ (PINTERFACE) (&sdpParseInterface),
+ sizeof(sdpParseInterface),
+ BTHDDI_SDP_PARSE_INTERFACE_VERSION_FOR_QI,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "QueryInterface failed for Interface sdp parse interface, version %d, Status code %!STATUS!\n",
+ BTHDDI_SDP_PARSE_INTERFACE_VERSION_FOR_QI,
+ status);
+
+ goto exit;
+ }
+
+ //
+ // Once we retrieved the server SDP record, we retrieve
+ // PSM from this record.
+ //
+ // We store this Psm in our file context and use it in open
+ // and close channel BRBs.
+ //
+
+ status = BthEchoCliRetrievePsmFromSdpRecord(
+ &sdpParseInterface,
+ serverSdpRecord,
+ &fileCtx->ServerPsm
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+ //
+ // Open remote connection to the server
+ // We format Create request for this purpose.
+ //
+ // This means that any cancellation of Create propagates
+ // to cancellation of open channel BRB.
+ //
+ status = BthEchoCliOpenRemoteConnection(
+ devCtx,
+ FileObject,
+ Request
+ );
+
+exit:
+ if (NULL != serverSdpRecord)
+ {
+ //
+ // Free the Server SDP record
+ //
+ ExFreePoolWithTag(serverSdpRecord, POOLTAG_BTHECHOSAMPLE);
+ }
+
+ //
+ // If we failed we complete the request here
+ // If it succeeds RemoteConnectCompletion will complete the request
+ //
+
+ if (!NT_SUCCESS(status))
+ {
+ WdfRequestComplete(Request, status);
+ }
+}
+
+VOID
+BthEchoCliEvtFileClose(
+ _In_ WDFFILEOBJECT FileObject
+ )
+/*++
+Description:
+
+ This routine is invoked by Framework when I/O manager sends Close
+ IRP for a file.
+
+ In response we close the remote connection to the server.
+
+Arguments:
+
+ FileObject - File object corresponding to Close
+
+--*/
+{
+ PBTHECHOSAMPLE_CLIENT_CONTEXT devCtx;
+ PBTHECHO_CONNECTION connection;
+
+ PAGED_CODE();
+
+ devCtx = GetClientDeviceContext(WdfFileObjectGetDevice(FileObject));
+
+ connection = GetFileContext(FileObject)->Connection;
+
+ //
+ // Since this routine is called at passive level we can disconnect
+ // synchronously.
+ //
+ BthEchoConnectionObjectRemoteDisconnectSynchronously(
+ &(devCtx->Header),
+ connection
+ );
+}
+
diff --git a/bluetooth/bthecho/bthcli/sys/device.h b/bluetooth/bthecho/bthcli/sys/device.h
new file mode 100644
index 00000000..640cf2cf
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/device.h
@@ -0,0 +1,91 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ 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.
+
+Module Name:
+
+ Device.h
+
+Abstract:
+
+ Conext and function declarations for bthecho client device
+
+Environment:
+
+ Kernel mode only
+
+
+--*/
+
+#include "clisrv.h"
+
+typedef struct _BTHECHOSAMPLE_CLIENT_CONTEXT
+{
+ //
+ // Context common to client and server
+ //
+ BTHECHOSAMPLE_DEVICE_CONTEXT_HEADER Header;
+
+ //
+ // Server address
+ //
+ BTH_ADDR ServerBthAddress;
+
+} BTHECHOSAMPLE_CLIENT_CONTEXT, *PBTHECHOSAMPLE_CLIENT_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BTHECHOSAMPLE_CLIENT_CONTEXT, GetClientDeviceContext)
+
+typedef struct _BTHECHOSAMPLE_CLIENT_FILE_CONTEXT
+{
+ //
+ // Connection to server opened for this file
+ //
+ PBTHECHO_CONNECTION Connection;
+
+ //
+ // Server PSM
+ //
+ USHORT ServerPsm;
+} BTHECHOSAMPLE_CLIENT_FILE_CONTEXT, *PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT;
+
+//
+// Context for requests
+//
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BRB, GetRequestContext);
+
+//
+// Context for file objects
+//
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BTHECHOSAMPLE_CLIENT_FILE_CONTEXT, GetFileContext);
+
+NTSTATUS
+FORCEINLINE
+BthEchoCliContextInit(
+ PBTHECHOSAMPLE_CLIENT_CONTEXT context,
+ WDFDEVICE Device
+ )
+{
+ return BthEchoSharedDeviceContextHeaderInit(&context->Header, Device);
+}
+
+EVT_WDF_DRIVER_DEVICE_ADD BthEchoCliEvtDriverDeviceAdd;
+
+EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT BthEchoCliEvtDeviceSelfManagedIoInit;
+
+EVT_WDF_DEVICE_FILE_CREATE BthEchoCliEvtDeviceFileCreate;
+
+EVT_WDF_FILE_CLOSE BthEchoCliEvtFileClose;
+
+NTSTATUS
+BthEchoCliConnectionStateConnected(
+ _In_ WDFFILEOBJECT FileObject,
+ _In_ PBTHECHO_CONNECTION Connection
+ );
+
+
+
diff --git a/bluetooth/bthecho/bthcli/sys/driver.c b/bluetooth/bthecho/bthcli/sys/driver.c
new file mode 100644
index 00000000..3b576a3d
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/driver.c
@@ -0,0 +1,210 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ 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.
+
+Module Name:
+
+ Driver.c
+
+Abstract:
+
+ Driver object related functionality for bthecho client device
+
+Environment:
+
+ Kernel mode only
+
+
+--*/
+
+#include "clisrv.h"
+#include "driver.h"
+
+#if defined(EVENT_TRACING)
+//
+// The trace message header (.tmh) file must be included in a source file
+// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS
+// macro (defined in toaster.h). During the compilation, WPP scans the source
+// files for DoTraceMessage() calls and builds a .tmh file which stores a unique
+// data GUID for each message, the text resource string for each message,
+// and the data types of the variables passed in for each message. This file
+// is automatically generated and used during post-processing.
+//
+#include "driver.tmh"
+#else
+#define _DRIVER_NAME_ "BthEchoSampleCli"
+ULONG DebugLevel = TRACE_LEVEL_INFORMATION;
+ULONG DebugFlag = 0xff;
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (INIT, DriverEntry)
+#pragma alloc_text (PAGE, BthEchoCliEvtDriverCleanup)
+#endif
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded.
+
+Parameters Description:
+
+ DriverObject - represents the instance of the function driver that is loaded
+ into memory. DriverEntry must initialize members of DriverObject before it
+ returns to the caller. DriverObject is allocated by the system before the
+ driver is loaded, and it is released by the system after the system unloads
+ the function driver from memory.
+
+ RegistryPath - represents the driver specific path in the Registry.
+ The function driver can use the path to store driver related data between
+ reboots. The path does not store hardware instance specific data.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ NTSTATUS status;
+ WDFDRIVER driver;
+ WDF_OBJECT_ATTRIBUTES attributes;
+
+ WDF_DRIVER_CONFIG DriverConfig;
+ WDF_DRIVER_CONFIG_INIT(
+ &DriverConfig,
+ BthEchoCliEvtDriverDeviceAdd
+ );
+
+ WPP_INIT_TRACING( DriverObject, RegistryPath );
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.EvtCleanupCallback = BthEchoCliEvtDriverCleanup;
+
+ status = WdfDriverCreate(
+ DriverObject,
+ RegistryPath,
+ NULL,
+ &DriverConfig,
+ &driver
+ );
+
+ if(!NT_SUCCESS(status))
+ {
+ WPP_CLEANUP(DriverObject);
+ }
+
+ return status;
+}
+
+VOID
+BthEchoCliEvtDriverCleanup(
+ _In_ WDFOBJECT DriverObject
+ )
+/*++
+Routine Description:
+
+ Free resources allocated in DriverEntry that are automatically
+ cleaned up framework.
+
+Arguments:
+
+ DriverObject - handle to a WDF Driver object.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+ PAGED_CODE ();
+
+ //
+ // Driver remains unreferenced if EVENT_TRACING is not defined
+ // in which case traces are sent to debugger instead of ETW
+ //
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ WPP_CLEANUP( WdfDriverWdmGetDriverObject( DriverObject ) );
+}
+
+#if !defined(EVENT_TRACING)
+
+VOID
+TraceEvents (
+ _In_ ULONG DebugPrintLevel,
+ _In_ ULONG DebugPrintFlag,
+ _Printf_format_string_
+ _In_ PCSTR DebugMessage,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Debug print for the sample driver.
+
+Arguments:
+
+ TraceEventsLevel - print level between 0 and 3, with 3 the most verbose
+
+Return Value:
+
+ None.
+
+ --*/
+ {
+#if DBG
+#define TEMP_BUFFER_SIZE 1024
+ va_list list;
+ CHAR debugMessageBuffer[TEMP_BUFFER_SIZE];
+ NTSTATUS status;
+
+ va_start(list, DebugMessage);
+
+ if (DebugMessage) {
+
+ //
+ // Using new safe string functions instead of _vsnprintf.
+ // This function takes care of NULL terminating if the message
+ // is longer than the buffer.
+ //
+ status = RtlStringCbVPrintfA( debugMessageBuffer,
+ sizeof(debugMessageBuffer),
+ DebugMessage,
+ list );
+ if(!NT_SUCCESS(status)) {
+
+ DbgPrint (_DRIVER_NAME_": RtlStringCbVPrintfA failed 0x%x\n", status);
+ return;
+ }
+ if (DebugPrintLevel <= TRACE_LEVEL_ERROR ||
+ (DebugPrintLevel <= DebugLevel &&
+ ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) {
+ DbgPrint("%s %s", _DRIVER_NAME_, debugMessageBuffer);
+ }
+ }
+ va_end(list);
+
+ return;
+#else
+ UNREFERENCED_PARAMETER(DebugPrintLevel);
+ UNREFERENCED_PARAMETER(DebugPrintFlag);
+ UNREFERENCED_PARAMETER(DebugMessage);
+#endif
+}
+
+#endif
+
diff --git a/bluetooth/bthecho/bthcli/sys/driver.h b/bluetooth/bthecho/bthcli/sys/driver.h
new file mode 100644
index 00000000..94ff858b
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/driver.h
@@ -0,0 +1,34 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ 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.
+
+Module Name:
+
+ Driver.c
+
+Abstract:
+
+ Driver object related declarations for bthecho client device
+
+Environment:
+
+ Kernel mode only
+
+
+--*/
+
+//
+// WDFDRIVER Events
+//
+
+DRIVER_INITIALIZE DriverEntry;
+
+EVT_WDF_DRIVER_DEVICE_ADD BthEchoCliEvtDriverDeviceAdd;
+
+EVT_WDF_OBJECT_CONTEXT_CLEANUP BthEchoCliEvtDriverCleanup;
+
diff --git a/bluetooth/bthecho/bthcli/sys/queue.c b/bluetooth/bthecho/bthcli/sys/queue.c
new file mode 100644
index 00000000..6f1e244c
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/queue.c
@@ -0,0 +1,349 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ 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.
+
+Module Name:
+
+ Queue.c
+
+Abstract:
+
+ Read/write functionality for bthecho client
+
+Environment:
+
+ Kernel mode only
+
+
+--*/
+
+#include "clisrv.h"
+#include "device.h"
+#include "queue.h"
+
+#if defined(EVENT_TRACING)
+#include "queue.tmh"
+#endif
+
+void
+BthEchoCliReadWriteCompletion(
+ _In_ WDFREQUEST Request,
+ _In_ WDFIOTARGET Target,
+ _In_ PWDF_REQUEST_COMPLETION_PARAMS Params,
+ _In_ WDFCONTEXT Context
+ )
+/*++
+Description:
+
+ Completion routine for read/write requests
+
+ We receive l2ca transfer BRB as the context. This BRB
+ is part of the request context and doesn't need to be freed
+ explicitly.
+
+Arguments:
+
+ Request - Request that got completed
+ Target - Target to which request was sent
+ Params - Completion parameters for the request
+ Context - We receive BRB as the context
+
+--*/
+{
+ struct _BRB_L2CA_ACL_TRANSFER *brb;
+ size_t information;
+
+ UNREFERENCED_PARAMETER(Target);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT,
+ "I/O completion, status: %!STATUS!", Params->IoStatus.Status);
+
+ brb = (struct _BRB_L2CA_ACL_TRANSFER *) Context;
+
+ NT_ASSERT((brb != NULL));
+
+ //
+ // Bytes read/written are contained in Brb->BufferSize
+ //
+ information = brb->BufferSize;
+
+ //
+ // Complete the request
+ //
+ WdfRequestCompleteWithInformation(
+ Request,
+ Params->IoStatus.Status,
+ information
+ );
+}
+
+VOID
+BthEchoCliEvtQueueIoWrite(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t Length
+ )
+/*++
+Description:
+
+ This routine is invoked by the framework to deliver a
+ Write request to the driver.
+
+Arguments:
+
+ Queue - Queue delivering the request
+ Request - Write request
+ Length - Length of write
+
+--*/
+{
+ NTSTATUS status;
+ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx;
+ WDFMEMORY memory;
+ struct _BRB_L2CA_ACL_TRANSFER * brb = NULL;
+ PBTHECHO_CONNECTION connection;
+
+ UNREFERENCED_PARAMETER(Length);
+
+ connection = GetFileContext(WdfRequestGetFileObject(Request))->Connection;
+
+ DevCtx = GetClientDeviceContext(WdfIoQueueGetDevice(Queue));
+
+ status = WdfRequestRetrieveInputMemory(
+ Request,
+ &memory
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "WdfRequestRetrieveInputMemory failed, request 0x%p, Status code %!STATUS!\n",
+ Request,
+ status);
+
+ goto exit;
+ }
+
+ //
+ // Get the BRB from request context and initialize it as
+ // BRB_L2CA_ACL_TRANSFER BRB
+ //
+ brb = (struct _BRB_L2CA_ACL_TRANSFER *)GetRequestContext(Request);
+ DevCtx->Header.ProfileDrvInterface.BthReuseBrb(
+ (PBRB)brb,
+ BRB_L2CA_ACL_TRANSFER
+ );
+
+
+ //
+ // Format the Write request for L2Ca OUT transfer
+ //
+ // This routine allocates a BRB which is returned to us
+ // in brb parameter
+ //
+ // This BRB is freed by the completion routine is we send the
+ // request successfully, else it is freed by this routine.
+ //
+ status = BthEchoConnectionObjectFormatRequestForL2CaTransfer(
+ connection,
+ Request,
+ &brb,
+ memory,
+ ACL_TRANSFER_DIRECTION_OUT
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+ //
+ // Set a CompletionRoutine callback function.
+ //
+
+ WdfRequestSetCompletionRoutine(
+ Request,
+ BthEchoCliReadWriteCompletion,
+ brb
+ );
+
+ //
+ // Send the request down the stack
+ //
+ if (FALSE == WdfRequestSend(
+ Request,
+ DevCtx->Header.IoTarget,
+ NULL
+ ))
+ {
+ status = WdfRequestGetStatus(Request);
+
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL,
+ "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n",
+ Request,
+ brb,
+ status
+ );
+
+ goto exit;
+ }
+
+exit:
+ if (!NT_SUCCESS(status))
+ {
+ WdfRequestComplete(Request, status);
+ }
+}
+
+VOID
+BthEchoCliEvtQueueIoRead (
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t Length
+ )
+/*++
+Description:
+
+ This routine is invoked by the framework to deliver a
+ Read request to the driver.
+
+Arguments:
+
+ Queue - Queue delivering the request
+ Request - Read request
+ Length - Length of Read
+
+--*/
+{
+ NTSTATUS status;
+ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx;
+ WDFMEMORY memory;
+ struct _BRB_L2CA_ACL_TRANSFER * brb = NULL;
+ PBTHECHO_CONNECTION connection;
+
+ UNREFERENCED_PARAMETER(Length);
+
+ connection = GetFileContext(WdfRequestGetFileObject(Request))->Connection;
+
+ DevCtx = GetClientDeviceContext(WdfIoQueueGetDevice(Queue));
+
+ status = WdfRequestRetrieveOutputMemory(
+ Request,
+ &memory
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "WdfRequestRetrieveInputMemory failed, request 0x%p, Status code %!STATUS!\n",
+ Request,
+ status);
+
+ goto exit;
+ }
+
+ //
+ // Get the BRB from request context and initialize it as
+ // BRB_L2CA_ACL_TRANSFER BRB
+ //
+ brb = (struct _BRB_L2CA_ACL_TRANSFER *)GetRequestContext(Request);
+ DevCtx->Header.ProfileDrvInterface.BthReuseBrb(
+ (PBRB)brb,
+ BRB_L2CA_ACL_TRANSFER
+ );
+
+ //
+ // Format the Read request for L2Ca IN transfer
+ //
+ // This routine allocates a BRB which is returned to us
+ // in brb parameter
+ //
+ // This BRB is freed by the completion routine is we send the
+ // request successfully, else it is freed by this routine.
+ //
+ status = BthEchoConnectionObjectFormatRequestForL2CaTransfer(
+ connection,
+ Request,
+ &brb,
+ memory,
+ ACL_TRANSFER_DIRECTION_IN | ACL_SHORT_TRANSFER_OK
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto exit;
+ }
+
+ //
+ // Set a CompletionRoutine callback function.
+ //
+
+ WdfRequestSetCompletionRoutine(
+ Request,
+ BthEchoCliReadWriteCompletion,
+ brb
+ );
+
+ //
+ // Send the request down the stack
+ //
+ if (FALSE == WdfRequestSend(
+ Request,
+ DevCtx->Header.IoTarget,
+ NULL
+ ))
+ {
+ status = WdfRequestGetStatus(Request);
+
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL,
+ "Request send failed for request 0x%p, Brb 0x%p, Status code %!STATUS!\n",
+ Request,
+ brb,
+ status
+ );
+
+ goto exit;
+ }
+
+exit:
+ if (!NT_SUCCESS(status))
+ {
+ WdfRequestComplete(Request, status);
+ }
+}
+
+VOID
+BthEchoCliEvtQueueIoStop(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ ULONG ActionFlags
+ )
+/*++
+Description:
+
+ This routine is invoked by Framework when Queue is being stopped
+
+ We implement this routine to cancel any requests owned by our driver.
+
+ Without this Queue stop would wait indefinitely for requests to complete
+ during surprise remove.
+
+Arguments:
+
+ Queue - Framework queue being stopped
+ Request - Request owned by the driver
+ ActionFlags - Action flags
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Queue);
+ UNREFERENCED_PARAMETER(ActionFlags);
+
+ WdfRequestCancelSentRequest(Request);
+}
+
diff --git a/bluetooth/bthecho/bthcli/sys/queue.h b/bluetooth/bthecho/bthcli/sys/queue.h
new file mode 100644
index 00000000..22d00a42
--- /dev/null
+++ b/bluetooth/bthecho/bthcli/sys/queue.h
@@ -0,0 +1,31 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ 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.
+
+Module Name:
+
+ Queue.h
+
+Abstract:
+
+ Queue events for bthecho client
+
+Environment:
+
+ Kernel mode only
+
+
+--*/
+
+EVT_WDF_IO_QUEUE_IO_READ BthEchoCliEvtQueueIoRead ;
+
+EVT_WDF_IO_QUEUE_IO_WRITE BthEchoCliEvtQueueIoWrite;
+
+EVT_WDF_IO_QUEUE_IO_STOP BthEchoCliEvtQueueIoStop;
+
+EVT_WDF_REQUEST_COMPLETION_ROUTINE BthEchoCliReadWriteCompletion;