diff options
| author | Dave Wilson <[email protected]> | 2015-04-29 09:48:49 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-04-29 10:47:29 -0700 |
| commit | d40232638faaab19de557e70a3ee938da7a35295 (patch) | |
| tree | 14e61c973745949af186b7940e3a53d25322f5de /bluetooth/bthecho/bthcli | |
| parent | 02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff) | |
samples update for //build
Diffstat (limited to 'bluetooth/bthecho/bthcli')
| -rw-r--r-- | bluetooth/bthecho/bthcli/app/BthEcho.vcxproj | 191 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/app/BthEcho.vcxproj.Filters | 22 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/app/main.cpp | 182 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.inx | 101 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj | 201 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/BthEchoSampleCli.vcxproj.Filters | 43 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/client.c | 1207 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/client.h | 58 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/device.c | 458 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/device.h | 91 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/driver.c | 210 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/driver.h | 34 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/queue.c | 349 | ||||
| -rw-r--r-- | bluetooth/bthecho/bthcli/sys/queue.h | 31 |
14 files changed, 3178 insertions, 0 deletions
diff --git a/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj b/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj new file mode 100644 index 00000000..f982f9b7 --- /dev/null +++ b/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj @@ -0,0 +1,191 @@ +<?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>{B506A244-2ADC-4C65-85B8-8B19764B4849}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{ED7BAD90-5755-4501-83C1-30383B8C2D76}</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 /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</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" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>BthEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>BthEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>BthEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>BthEcho</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);cfgmgr32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);cfgmgr32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);cfgmgr32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\common\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);cfgmgr32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="main.cpp" /> + </ItemGroup> + <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/app/BthEcho.vcxproj.Filters b/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj.Filters new file mode 100644 index 00000000..bb3d32ad --- /dev/null +++ b/bluetooth/bthecho/bthcli/app/BthEcho.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{0A8DC157-9CD8-47FC-96AB-AB876FCB97C8}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{B0233FE1-6785-4466-886B-FC81C40F8257}</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>{6E8F0465-6F65-432E-9958-9869CF84EB6B}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/bluetooth/bthecho/bthcli/app/main.cpp b/bluetooth/bthecho/bthcli/app/main.cpp new file mode 100644 index 00000000..07b100e0 --- /dev/null +++ b/bluetooth/bthecho/bthcli/app/main.cpp @@ -0,0 +1,182 @@ +/*++ + +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: + + Main.cpp + +Abstract: + + A simple test for bthecho sample. + +Environment: + + user mode only + +--*/ + +#define INITGUID + +#include <windows.h> +#include <strsafe.h> +#include <stdio.h> +#include <stdlib.h> +#include <cfgmgr32.h> + +#include "public.h" + +char testData[] = "WDF Bluetooth Sample Echo"; +char replyData[sizeof(testData)]; + +DWORD +GetDevicePath( + _In_ LPGUID InterfaceGuid, + _Out_ LPWSTR * DevicePath + ); + +BOOL +DoEcho( + HANDLE hDevice + ); + +VOID +__cdecl +wmain() +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + BOOL echo = TRUE; + LPWSTR devicePath = NULL; + DWORD err = GetDevicePath((LPGUID)&BTHECHOSAMPLE_DEVICE_INTERFACE, &devicePath); + + if (ERROR_SUCCESS != err) { + printf("Failed to find the BTHECHO device\n"); + exit(1); + } + + hDevice = CreateFile(devicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Failed to open device. Error %d\n",GetLastError()); + LocalFree(devicePath); + exit(1); + } + + printf("Opened device successfully\n"); + + while (echo) + { + echo = DoEcho(hDevice); + } + + if (INVALID_HANDLE_VALUE != hDevice) { + CloseHandle(hDevice); + printf("Closed device\n"); + } + + if (NULL != devicePath) { + LocalFree(devicePath); + } +} + +BOOL +DoEcho( + HANDLE hDevice + ) +{ + BOOL retval = FALSE; + DWORD cbWritten = 0; + DWORD cbRead = 0; + + BOOL bRet = WriteFile( + hDevice, + testData, + sizeof(testData), + &cbWritten, + NULL + ); + + if (!bRet) + { + printf("Write failed. Error: %d\n", GetLastError()); + goto exit; + } + else + { + printf("Written \t\t%d bytes: %s\n", cbWritten, testData); + } + + bRet = ReadFile( + hDevice, + replyData, + cbWritten, + &cbRead, + NULL + ); + + if (!bRet) + { + printf("Read failed. Error: %d\n", GetLastError()); + goto exit; + } + else + { + printf("Reply from server \t%d bytes: %s\n", cbRead, replyData); + } + + if (cbRead == cbWritten) + { + retval = memcmp(replyData, testData, cbRead) ? FALSE : TRUE; + } + +exit: + return retval; +} + +DWORD +GetDevicePath( + _In_ LPGUID InterfaceGuid, + _Out_ LPWSTR * DevicePath + ) +{ + CONFIGRET cmRet = CR_SUCCESS; + ULONG interfaceListSize = 0; + + *DevicePath = NULL; + + cmRet = CM_Get_Device_Interface_List_Size_Ex(&interfaceListSize, InterfaceGuid, 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT, NULL); + if (cmRet != CR_SUCCESS) { + goto exit; + } + + *DevicePath = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, interfaceListSize * sizeof((*DevicePath)[0])); + if (NULL == *DevicePath) { + cmRet = CR_OUT_OF_MEMORY; + goto exit; + } + + cmRet = CM_Get_Device_Interface_List_Ex(InterfaceGuid, 0, *DevicePath, interfaceListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT, NULL); + +exit: + + if (cmRet != CR_SUCCESS) { + if (NULL != *DevicePath) { + LocalFree(*DevicePath); + *DevicePath = NULL; + } + } + + return CM_MapCrToWin32Err(cmRet, ERROR_UNIDENTIFIED_ERROR); +} + 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; |
