Opening a Bluetooth connection between two devices is a fast and energy efficient way to communicate data over a short distance. Bluetooth connections allow for smartphones, computers, cars, and even IoT devices to communicate all over a frequency that operates at ~ 2480 MHz. In my experience working with Bluetooth, I have seen connections go up fairly easily or be very stubborn and not want to connect at all. Generally it seems harder to connect two devices that are not from the same manufacturer. So, what do you do when connections are being stubborn? Do you try and reconnect and just hope for the best, or is there a better way to see what is going on with these stubborn connections? The answer to this probably depends on what operating system you are running. On macOS there is a tool called PacketLogger that allows you to identify the general flow of Bluetooth packets in and out of the machine. Windows does not provide any straight forward Bluetooth packet capturing mechanism that I am aware of. Linux however, does provide the best flexibility by allowing the user to run a packet capture right off any Bluetooth interface. And that is why I wanted to write this tutorial, to provide insight on how to use TCPDump to capture Bluetooth packets on Linux and to provide more insight while debugging stubborn Bluetooth connection issues.
NOTE: This tutorial was created using a Ubuntu 16.04 as the host machine, running Bluetooth 5.37 and a macOS 10.14 as the controller machine, running Bluetooth 6.0. This example sets up a Bluetooth connection between two machines and transfers a file from one to the other. The connection and file transfer is all captured via TCPDump for analysis in Wireshark.
Setting up Linux for a Bluetooth Packet Capture 👨💻
Capturing Bluetooth on Linux can only be done if your kernel is 2.4.6 or later and includes the BlueZ stack within it. Next you will need a version of Libpcap 0.9.6 and later install on your Linux distro to run TCPDump. To check which version of BlueZ, Libpcap, and TCPdump you have installed, run the following commands:
# Check version of BlueZ $ bluetoothd -v # Check version of tcpdump and libpcap $ tcpdump --version
Once you have validated that you have the correct versions of BlueZ, Libpcap, and TCPdump it's time to check for a Bluetooth interface that TCPDump can capture from. To do this, run this command:
# Check for interfaces (may need sudo) $ tcpdump -D # Should produce a result like this if your Bluetooth interface is plugged in: 1. en0 [Up, Running] (Added as an example) 2. any [Up, Running] (Added as an example) ... 6.bluetooth0 (Bluetooth adapter number 0) 7.bluetooth1 (Bluetooth adapter number 1) (For more than one bluetooth adapter) ...
As you can see from the list above, the bluetooth0 interface is available. If I had more than one Bluetooth interface visible I would see bluetooth0 and bluetooth1 both available.
Capturing and Debugging Bluetooth Packets 🕵️♂️
Now that we know the name of the Bluetooth interface let's setup a capture on bluetooth0 to see if there is any explanation for the connection issues. To setup the capture, use TCPDump on the Linux machine to capture and write the packet data from the bluetooth0 interface to a pcap file for later examination. Next, attempt to establish the Bluetooth connection between the Linux and macOS machine and attempt to send a file or tow over that connection to provide some clues as to what might be happening. To setup a TCPDump capture, run this command:
# Capture bluetooth packets and write them to a pcap file called bluetooth0_capture_12_10.pcap $ tcpdump -i bluetooth0 -w bluetooth0_capture_12_12.pcap
During this capture I was able to successfully setup a Bluetooth connection between the two machines. However, I tried on two different occasions to send a file from Linux to macOS without success. Opening up the packet capture in Wireshark I can see the communication between the two machines and have highlighted the two sets of packets showing where Linux contacts macOS and asks if OBEX protocol is supported for file transfer. macOS then responds with an incomplete Service Search Attribute Response packet, meaning that file transfer is not enabled on macOS over Bluetooth. This is a great find, opening up the actual packet trace in Wireshark allowed me to fully diagnose what the issue is between macOS and Linux and now I can enable Bluetooth file sharing on macOS and try this test again.
After enabling Bluetooth file sharing on macOS I ran the same packet capture again and was able to successfully transfer the file from Linux to macOS. I was also able to see this file being transferred in the packet trace. The first thing I took a look at was the original connection setup packets seen in my failing case. The Service Search Attribute Response packet from macOS is now populated with all of the information needed to start the file transfer over OBEX. Next, in the screen shot above you can see the OBEX connection going up, macOS confirming it, and then Linux doing a "Put continue" for the "Bluetooth.txt" file. After the file is successfully sent, macOS confirms the transfer of the file and the OBEX connection is taken down. We have success!
In Summary ⌛️
Debugging stubborn Bluetooth connections can be difficult if you are not testing from macOS or Linux. As I have demonstrated in this tutorial, if you can find a way to run your Bluetooth connection through Linux there is a great opportunity for debugging what is happening in your connection using TCPDump and Wireshark. While this tutorial uses macOS as the slave, this could just as easily be a mobile, IoT, or any other smart device that you need to troubleshoot the connection with to Linux. I hope you have enjoyed this tutorial and please let me know if you have any questions, comments, concerns, or any other general feedback on this tutorial by leaving a comment. I will try and address all comments as soon as I am able to. Thank you!