Querying for Bluetooth interfaces

The Bluetooth driver stack exposes the following interfaces that profile drivers can use to interact with Bluetooth devices.

Interface Description
GUID_BTHDDI_SDP_NODE_INTERFACE Profile drivers query for the GUID_BTHDDI_SDP_NODE_INTERFACE to obtain pointers to functions that allow them to create Service Discovery Protocol (SDP) records.

This interface corresponds to the BTHDDI_SDP_NODE_INTERFACE structure.
GUID_BTHDDI_SDP_PARSE_INTERFACE Profile drivers query for the GUID_BTHDDI_SDP_PARSE_INTERFACE to obtain pointers to functions that allow them to parse SDP records.

This interface corresponds to the BTHDDI_SDP_PARSE_INTERFACE structure.
GUID_BTHDDI_PROFILE_DRIVER_INTERFACE Profile drivers query for the BTHDDI_PROFILE_DRIVER_INTERFACE to obtain pointers to functions that allow them to create, allocate, reuse, and free BRBs.

This interface corresponds to the BTH_PROFILE_DRIVER_INTERFACE structure.

To obtain any of these interfaces, a profile driver must first build and send an IRP_MN_QUERY_INTERFACE IRP to the Bluetooth driver stack.

The following procedure is the general process to obtain one of these interfaces.

To query for an interface

  1. Allocate and initialize an IRP.
  2. Allocate and initialize an instance of the interface.
  3. Specify the major and minor function codes to query for the interface.
  4. Specify the interface to query for.
  5. Pass the IRP down the driver stack to be processed.

The following pseudocode example demonstrates how to set up an IRP_MN_QUERY_INTERFACE IRP to query the Bluetooth driver stack for the GUID_BTHDDI_PROFILE_DRIVER_INTERFACE. For readability, the example does not demonstrate error handling.

#include <bthddi.h>

...

// Define a custom pool tag to identify your profile driver's dynamic memory allocations. You should change this tag to easily identify your driver's allocations from other drivers.
#define PROFILE_DRIVER_POOL_TAG '_htB'

PIRP Irp;
Irp = IoAllocateIrp( DeviceExtension->ParentDeviceObject->StackSize, FALSE );

PBTH_PROFILE_DRIVER_INTERFACE BthInterface; // Define storage for an instance of the BTH_PROFILE_DRIVER_INTERFACE structure
BthInterface = ExAllocatePoolWithTag( NonPagedPool, sizeof( BTH_PROFILE_DRIVER_INTERFACE ), PROFILE_DRIVER_POOL_TAG );

// Zero the memory associated with the structure
RtlZeroMemory( BthInterface, sizeof( BTH_PROFILE_DRIVER_INTERFACE ) );

// Set up the next IRP stack location
PIO_STACK_LOCATION NextIrpStack;
NextIrpStack = IoGetNextIrpStackLocation( Irp );
NextIrpStack->MajorFunction = IRP_MJ_PNP;
NextIrpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
NextIrpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BTHDDI_PROFILE_DRIVER_INTERFACE;
NextIrpStack->Parameters.QueryInterface.Size = sizeof( BTH_PROFILE_DRIVER_INTERFACE );
NextIrpStack->Parameters.QueryInterface.Version = BTHDDI_PROFILE_DRIVER_INTERFACE_VERSION_FOR_QI;
NextIrpStack->Parameters.QueryInterface.Interface = (PINTERFACE) BthInterface;
NextIrpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;

// Pass the IRP down the driver stack
NTSTATUS Status;
Status = IoCallDriver( DeviceExtension->NextLowerDriver, Irp );

If the IRP returns successfully, the profile driver can then access and use the function pointers that are contained in the interface.