From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 76 ++++++++++++++++++++++++++++ dlls/winebth.sys/unixlib.c | 9 ++++ dlls/winebth.sys/unixlib.h | 7 +++ dlls/winebth.sys/unixlib_priv.h | 1 + dlls/winebth.sys/winebluetooth.c | 11 ++++ dlls/winebth.sys/winebth.c | 86 +++++++++++++++++++++++++++++++- dlls/winebth.sys/winebth_priv.h | 12 ++++- include/wine/winebth.h | 7 +++ 8 files changed, 205 insertions(+), 4 deletions(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 9a4aa89bbee..36f5a8cc467 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -1266,6 +1266,76 @@ NTSTATUS bluez_device_disconnect( void *connection, const char *device_path ) return STATUS_SUCCESS; }
+static BOOL bluez_event_list_queue_new_event( struct list *event_list, + enum winebluetooth_watcher_event_type event_type, + union winebluetooth_watcher_event_data event ); +struct bluez_device_pair_data +{ + IRP *irp; + struct bluez_watcher_ctx *watcher_ctx; +}; + +static void bluez_device_pair_callback( DBusPendingCall *pending, void *param ) +{ + struct bluez_device_pair_data *data = param; + DBusMessage *reply; + DBusError error; + union winebluetooth_watcher_event_data event = {0}; + + event.pairing_finished.irp = data->irp; + reply = p_dbus_pending_call_steal_reply( pending ); + p_dbus_error_init( &error ); + if (p_dbus_set_error_from_message( &error, reply )) + { + event.pairing_finished.result = bluez_dbus_error_to_ntstatus( &error ); + ERR( "Failed to pair: %s: %s\n", debugstr_a( error.name ), debugstr_a( error.message ) ); + } + p_dbus_error_free( &error ); + + bluez_event_list_queue_new_event( &data->watcher_ctx->event_list, + BLUETOOTH_WATCHER_EVENT_TYPE_PAIRING_FINISHED, event ); + p_dbus_message_unref( reply ); + p_dbus_pending_call_unref( pending ); +} + +NTSTATUS bluez_device_start_pairing( void *connection, void *watcher_ctx, struct unix_name *device, IRP *irp ) +{ + DBusMessage *request; + DBusPendingCall *pending_call = NULL; + struct bluez_device_pair_data *data; + dbus_bool_t success; + + TRACE( "(%p, %p, %s, %p)\n", connection, watcher_ctx, debugstr_a( device->str ), irp ); + + request = p_dbus_message_new_method_call( BLUEZ_DEST, device->str, BLUEZ_INTERFACE_DEVICE, "Pair" ); + if (!request) + return STATUS_NO_MEMORY; + + data = malloc( sizeof( *data ) ); + if (!data) + { + p_dbus_message_unref( request ); + return STATUS_NO_MEMORY; + } + data->irp = irp; + data->watcher_ctx = watcher_ctx; + success = p_dbus_connection_send_with_reply( connection, request, &pending_call, bluez_timeout ); + p_dbus_message_unref( request ); + if (!success) + return STATUS_NO_MEMORY; + if (!pending_call) + return STATUS_INTERNAL_ERROR; + if (!p_dbus_pending_call_set_notify( pending_call, bluez_device_pair_callback, data, free )) + { + p_dbus_pending_call_cancel( pending_call ); + p_dbus_pending_call_unref( pending_call ); + return STATUS_NO_MEMORY; + } + + p_dbus_pending_call_unref( pending_call ); + return STATUS_PENDING; +} + struct bluez_watcher_event { struct list entry; @@ -1825,6 +1895,8 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher ) case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED: unix_name_free( (struct unix_name *)event1->event.device_props_changed.device.handle ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_PAIRING_FINISHED: + break; } free( event1 ); } @@ -2195,5 +2267,9 @@ NTSTATUS bluez_device_disconnect( void *connection, const char *device_path ) { return STATUS_NOT_SUPPORTED; } +NTSTATUS bluez_device_start_pairing( void *connection, void *watcher_ctx, struct unix_name *device, IRP *irp ) +{ + return STATUS_NOT_SUPPORTED; +}
#endif /* SONAME_LIBDBUS_1 */ diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index 249137dd502..543c6d2ff1a 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -240,6 +240,14 @@ static NTSTATUS bluetooth_device_disconnect( void *args ) return bluez_device_disconnect( dbus_connection, params->device->str ); }
+static NTSTATUS bluetooth_device_start_pairing( void *args ) +{ + struct bluetooth_device_start_pairing_params *params = args; + + if (!dbus_connection) return STATUS_NOT_SUPPORTED; + return bluez_device_start_pairing( dbus_connection, bluetooth_watcher, params->device, params->irp ); +} + static NTSTATUS bluetooth_get_event( void *args ) { struct bluetooth_get_event_params *params = args; @@ -262,6 +270,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = {
bluetooth_device_free, bluetooth_device_disconnect, + bluetooth_device_start_pairing,
bluetooth_auth_agent_enable_incoming, bluetooth_auth_send_response, diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index 7357f777804..273023f5b16 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -100,6 +100,12 @@ struct bluetooth_auth_send_response_params BOOL *authenticated; };
+struct bluetooth_device_start_pairing_params +{ + unix_name_t device; + IRP *irp; +}; + struct bluetooth_get_event_params { struct winebluetooth_event result; @@ -119,6 +125,7 @@ enum bluetoothapis_funcs
unix_bluetooth_device_free, unix_bluetooth_device_disconnect, + unix_bluetooth_device_start_pairing,
unix_bluetooth_auth_agent_enable_incoming, unix_bluetooth_auth_send_response, diff --git a/dlls/winebth.sys/unixlib_priv.h b/dlls/winebth.sys/unixlib_priv.h index a9c1bc0f080..2ee0272f215 100644 --- a/dlls/winebth.sys/unixlib_priv.h +++ b/dlls/winebth.sys/unixlib_priv.h @@ -62,6 +62,7 @@ extern NTSTATUS bluez_auth_agent_send_response( void *auth_agent, struct unix_na BLUETOOTH_AUTHENTICATION_METHOD method, UINT32 numeric_or_passkey, BOOL negative, BOOL *authenticated ); extern NTSTATUS bluez_device_disconnect( void *connection, const char *device_path ); +extern NTSTATUS bluez_device_start_pairing( void *dbus_connection, void *watcher_ctx, struct unix_name *device, IRP *irp ); extern NTSTATUS bluez_watcher_init( void *connection, void **ctx ); extern void bluez_watcher_close( void *connection, void *ctx ); #endif /* __WINE_WINEBTH_UNIXLIB_PRIV_H */ diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index ca234b98f4b..448fd3f4dda 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -177,6 +177,17 @@ NTSTATUS winebluetooth_auth_send_response( winebluetooth_device_t device, BLUETO return UNIX_BLUETOOTH_CALL( bluetooth_auth_send_response, &args ); }
+NTSTATUS winebluetooth_device_start_pairing( winebluetooth_device_t device, IRP *irp ) +{ + struct bluetooth_device_start_pairing_params args = {0}; + + TRACE( "(%p)\n", (void *)device.handle ); + + args.device = device.handle; + args.irp = irp; + return UNIX_BLUETOOTH_CALL( bluetooth_device_start_pairing, &args ); +} + NTSTATUS winebluetooth_get_event( struct winebluetooth_event *result ) { struct bluetooth_get_event_params params = {0}; diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 694c9f1d629..47006d04aad 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -81,6 +81,9 @@ struct bluetooth_radio
CRITICAL_SECTION remote_devices_cs; struct list remote_devices; /* Guarded by remote_devices_cs */ + + /* Guarded by device_list_cs */ + LIST_ENTRY irp_list; };
struct bluetooth_remote_device @@ -329,6 +332,47 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) LeaveCriticalSection( &ext->remote_devices_cs ); break; } + case IOCTL_WINEBTH_RADIO_START_AUTH: + { + const struct winebth_radio_start_auth_params *params = irp->AssociatedIrp.SystemBuffer; + struct bluetooth_remote_device *device; + + if (!params) + { + status = STATUS_INVALID_PARAMETER; + break; + } + if (insize < sizeof( *params )) + { + status = STATUS_INVALID_BUFFER_SIZE; + break; + } + + status = STATUS_DEVICE_DOES_NOT_EXIST; + EnterCriticalSection( &device_list_cs ); + EnterCriticalSection( &ext->remote_devices_cs ); + LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) + { + BOOL matches; + EnterCriticalSection( &device->props_cs ); + matches = device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS && + device->props.address.ullLong == params->address; + LeaveCriticalSection( &device->props_cs ); + if (matches) + { + status = winebluetooth_device_start_pairing( device->device, irp ); + if (status == STATUS_PENDING) + { + IoMarkIrpPending( irp ); + InsertTailList( &ext->irp_list, &irp->Tail.Overlay.ListEntry ); + } + break; + } + } + LeaveCriticalSection( &ext->remote_devices_cs ); + LeaveCriticalSection( &device_list_cs ); + break; + } case IOCTL_WINEBTH_RADIO_REMOVE_DEVICE: { const BTH_ADDR *param = irp->AssociatedIrp.SystemBuffer; @@ -369,8 +413,11 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) break; }
- irp->IoStatus.Status = status; - IoCompleteRequest( irp, IO_NO_INCREMENT ); + if (status != STATUS_PENDING) + { + irp->IoStatus.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } return status; }
@@ -483,6 +530,7 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added
InitializeCriticalSection( &device->props_cs ); InitializeCriticalSection( &device->remote_devices_cs ); + InitializeListHead( &device->irp_list );
EnterCriticalSection( &device_list_cs ); list_add_tail( &device_list, &device->entry ); @@ -797,6 +845,16 @@ static void bluetooth_radio_report_auth_event( struct winebluetooth_auth_event e ExFreePool( notification ); }
+static void complete_irp( IRP *irp, NTSTATUS result ) +{ + EnterCriticalSection( &device_list_cs ); + RemoveEntryList( &irp->Tail.Overlay.ListEntry ); + LeaveCriticalSection( &device_list_cs ); + + irp->IoStatus.Status = result; + IoCompleteRequest( irp, IO_NO_INCREMENT ); +} + static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) { NTSTATUS status; @@ -832,6 +890,10 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED: bluetooth_radio_update_device_props( event->event_data.device_props_changed); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_PAIRING_FINISHED: + complete_irp( event->event_data.pairing_finished.irp, + event->event_data.pairing_finished.result ); + break; default: FIXME( "Unknown bluetooth watcher event code: %#x\n", event->event_type ); } @@ -994,6 +1056,21 @@ static void bluetooth_radio_set_properties( DEVICE_OBJECT *obj, sizeof( props->version ), &props->version ); }
+/* Caller should hold device_list_cs. */ +static void remove_pending_irps( struct bluetooth_radio *radio ) +{ + LIST_ENTRY *entry; + IRP *irp; + + while ((entry = RemoveHeadList( &radio->irp_list )) != &radio->irp_list) + { + irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry ); + irp->IoStatus.Status = STATUS_DELETE_PENDING; + irp->IoStatus.Information = 0; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } +} + static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); @@ -1031,6 +1108,10 @@ static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) break; case IRP_MN_REMOVE_DEVICE: assert( device->removed ); + EnterCriticalSection( &device_list_cs ); + remove_pending_irps( device ); + LeaveCriticalSection( &device_list_cs ); + if (device->bthport_symlink_name.Buffer) { IoSetDeviceInterfaceState(&device->bthport_symlink_name, FALSE); @@ -1048,6 +1129,7 @@ static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) break; case IRP_MN_SURPRISE_REMOVAL: EnterCriticalSection( &device_list_cs ); + remove_pending_irps( device ); if (!device->removed) { device->removed = TRUE; diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 5456acdd7a3..5addf6303ec 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -214,7 +214,7 @@ NTSTATUS winebluetooth_device_disconnect( winebluetooth_device_t device );
NTSTATUS winebluetooth_auth_send_response( winebluetooth_device_t device, BLUETOOTH_AUTHENTICATION_METHOD method, UINT32 numeric_or_passkey, BOOL negative, BOOL *authenticated ); - +NTSTATUS winebluetooth_device_start_pairing( winebluetooth_device_t device, IRP *irp ); enum winebluetooth_watcher_event_type { BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED, @@ -222,7 +222,8 @@ enum winebluetooth_watcher_event_type BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED, BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED, BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED, - BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED + BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED, + BLUETOOTH_WATCHER_EVENT_TYPE_PAIRING_FINISHED, };
struct winebluetooth_watcher_event_radio_added @@ -264,6 +265,12 @@ struct winebluetooth_watcher_event_device_removed winebluetooth_device_t device; };
+struct winebluetooth_watcher_event_pairing_finished +{ + IRP *irp; + NTSTATUS result; +}; + union winebluetooth_watcher_event_data { struct winebluetooth_watcher_event_radio_added radio_added; @@ -272,6 +279,7 @@ union winebluetooth_watcher_event_data struct winebluetooth_watcher_event_device_added device_added; struct winebluetooth_watcher_event_device_removed device_removed; struct winebluetooth_watcher_event_device_props_changed device_props_changed; + struct winebluetooth_watcher_event_pairing_finished pairing_finished; };
struct winebluetooth_watcher_event diff --git a/include/wine/winebth.h b/include/wine/winebth.h index d0fb06c11e0..c785d08d88e 100644 --- a/include/wine/winebth.h +++ b/include/wine/winebth.h @@ -32,6 +32,8 @@ /* Ask the system's Bluetooth service to send all incoming authentication requests to Wine. */ #define IOCTL_WINEBTH_AUTH_REGISTER CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xa8, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WINEBTH_RADIO_SEND_AUTH_RESPONSE CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xa9, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* Initiate the authentication procedure with a remote device. */ +#define IOCTL_WINEBTH_RADIO_START_AUTH CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xaa, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WINEBTH_RADIO_REMOVE_DEVICE CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xab, METHOD_BUFFERED, FILE_ANY_ACCESS)
DEFINE_GUID( GUID_WINEBTH_AUTHENTICATION_REQUEST, 0xca67235f, 0xf621, 0x4c27, 0x85, 0x65, 0xa4, @@ -68,6 +70,11 @@ struct winebth_radio_send_auth_response_params unsigned int authenticated : 1; };
+struct winebth_radio_start_auth_params +{ + BTH_ADDR address; +}; + #pragma pack(pop)
#endif /* __WINEBTH_H__ */