Blog

Bluetooth en Linux: OPP, ERTM, SELinux, Bluez, obex, y firmwares.

Bluetooth en Linux: OPP, ERTM, SELinux, Bluez, obex, y firmwares.

Siempre he tenido problemas para enviar y recibir ficheros por Bluetooth entre mi móvil (Xperia X Compact) y Linux. Uso el perfil OPP (Object Push Profile). En un viejo Motorola XT1039 podía recibir pero no enviar.


INCISO: Para los que tengan un mando Xbox por Bluetooth…

También tengo un mando de Xbox conectado por bluetooth. Para que funcione es necesario deshabilitar ERTM, Enhanced Re-Transmission Mode (capa «L2CAP» del stack de Bluetooth). Pues… sorpresa: sin ese modo no funciona bien en el Xperia, así que que no podremos utilizar el mando al mismo tiempo que OPP. Al enviar al móvil un fichero sin ERTM salta: «Error ocurred: Unable to find service record». En mi caso utilizo más a menudo el mando que OPP, así que lo dejo deshabilitado por defecto en mi /etc/modprobe.d/99-xpadneo-bluetooth.conf

options bluetooth disable_ertm=y

…y cuando quiera pasar ficheros, lo habilito temporalmente:

[root@localhost j]# echo 0 > /sys/module/bluetooth/parameters/disable_ertm

y reinicio los módulos btbcm (BlueTooth BroadCoM), btusb (Bluetooth USB), y el servicio de bluetooth (BlueZ).

#!/bin/bash
sudo rmmod btusb && sudo rmmod btbcm
sudo modprobe btbcm && sudo modprobe btusb
sudo systemctl restart bluetooth

…y luego deshago el cambio:

[root@localhost j]# echo 1 > /sys/module/bluetooth/parameters/disable_ertm

Para facilitar las cosas, lo tengo como dos funciones en ~/.bashrc:

modo_opp() (
        sudo bash -c 'echo 0 > /sys/module/bluetooth/parameters/disable_ertm'
        sudo rmmod btusb && sudo rmmod btbcm
        sudo modprobe btbcm && sudo modprobe btusb
        sudo systemctl restart bluetooth
)

modo_xbox() (
        sudo bash -c 'echo 1 > /sys/module/bluetooth/parameters/disable_ertm'
)

FIN DEL INCISO


Ahora podía recibir, pero seguía sin poder enviar. Intenté ver los errores del servicio de bluetooth (Bluez). Para ello, paramos el servicio de systemd:

sudo systemctl stop bluetooth

…y lo iniciamos por consola con información de depuración:

sudo /usr/libexec/bluetooth/bluetoothd -d -n

Al enviar veía el siguiente error, y después el daemon petaba:

bluetoothd[XXXX]: Disconnected from D-Bus. Exiting.

Después de dar muchas vueltas, encontré este enlace:

> Everything looks fine until I turn on a bluetooth device that was
> already paired and trusted. As far as I can tell, it connects correctly,
> but then the bluetoothd log shows
>
> May 10 10:18:41 raspberrypi.local bluetoothd[3127]: profiles/audio/transport.c:transport_update_playing() /org/bluez/hci0/dev_EC_81_93_4A_C7_7E/fd0 State=TRANSPORT_STATE_ACTIVE Playing=1
> May 10 10:18:41 raspberrypi.local bluetoothd[3127]: Disconnected from D-Bus. Exiting.

I suspect this is due to fd hand over, I usually have to
SELINUX=disabled to disable SELinux policies when running bluetoothd
from source because it seems there is some policy the prevents fd
passing over D-Bus,  we should probably add this to HACKING if we
confirm that this is in fact SELinux policy.

Efectivamente, el culpable era SELinux. Lo dejé en Permissive:

sudo setenforce Permissive

Ahora bluetoothd no terminaba, pero veía un error en OBEX, que es quien se encarga de registrar, entre otros, el perfil OPP. Al hacer systemctl --user status obex aparecía un mensaje como éste:

obexd[XXXX]: PUT(0x2), Forbidden(0x43)

Estuve viendo los errores de log más detalladamente haciendo:

systemctl --user stop obex
/usr/libexec/bluetooth/obexd -d -n

Encontré que con la opción -a, para autoaceptar ficheros, desaparecía el problema:

/usr/libexec/bluetooth/obexd -d -n -a

En teoría debería aparecer una ventana para aceptar o rechazar el fichero, pero con blueberry, el gestor de Bluetooth de GNOME, no me mostraba nada. Quizá porque estoy utilizándolo en XFCE. Quité la opción -a de obex e instalé otro gestor de Bluetooth, blueman (sudo dnf install blueman), que me mostraba correctamente la mencionada ventana. Deshabilité blueberry del inicio de sesión de XFCE. Además, es necesario este comando:

gsettings set org.blueberry obex-enabled false

Ahora por fin funcionaba el envío y recepción de ficheros.

Otros detalles

En lugar del «agente obex» de la interfaz gráfica de blueman (registrado en org.bluez.obex.Agent), también podemos utilizar un «agente obex» en terminal, bt-obex. Es últil para depurar:

bt-obex -s "/tmp"

También he instalado un paquete que contiene firmwares para Bluetooth de Broadcom:

sudo dnf install broadcom-bt-firmware

No sé si realmente ha influído, pero creo que no está de más. Sin esto, el kernel se queja en dmesg con errores como éste:

bluetooth hci0: Direct firmware load for brcm/BCM<...>.hcd failed with error -2

Esto instala varios ficheros en /lib/firmware/brcm/, entre otros el mío, BCM20702A1-050d-065a.hcd.