'Bluetooth pairing in C blueZ on Linux
I cannot find any reference on how to pair a bluetooth device on linux in a program written in C using the BlueZ Bluetooth libraries. I already managed to do a HCI level query to get devices along with thier RSSI levels (during the device discovery) but currently I am stuck with this. I saw a suggestion to use the DBUS api for the blueZ-simple-agent - but is there any way to avoid this and just use some C level methods from BlueZ?
Solution 1:[1]
Authentication code from hcitool
(original source code can see at http://git.kernel.org/cgit/bluetooth/bluez.git/tree/tools/hcitool.c)
/* Request authentication */
static void cmd_auth(int dev_id, int argc, char **argv)
{
struct hci_conn_info_req *cr;
bdaddr_t bdaddr;
int opt, dd;
for_each_opt(opt, auth_options, NULL) {
switch (opt) {
default:
printf("%s", auth_help);
return;
}
}
helper_arg(1, 1, &argc, &argv, auth_help);
str2ba(argv[0], &bdaddr);
if (dev_id < 0) {
dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
if (dev_id < 0) {
fprintf(stderr, "Not connected.\n");
exit(1);
}
}
dd = hci_open_dev(dev_id);
if (dd < 0) {
perror("HCI device open failed");
exit(1);
}
cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
if (!cr) {
perror("Can't allocate memory");
exit(1);
}
bacpy(&cr->bdaddr, &bdaddr);
cr->type = ACL_LINK;
if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
perror("Get connection info failed");
exit(1);
}
if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000) < 0) {
perror("HCI authentication request failed");
exit(1);
}
free(cr);
hci_close_dev(dd);
}
And setting up PIN
/* Activate encryption */
static void cmd_enc(int dev_id, int argc, char **argv)
{
struct hci_conn_info_req *cr;
bdaddr_t bdaddr;
uint8_t encrypt;
int opt, dd;
for_each_opt(opt, enc_options, NULL) {
switch (opt) {
default:
printf("%s", enc_help);
return;
}
}
helper_arg(1, 2, &argc, &argv, enc_help);
str2ba(argv[0], &bdaddr);
if (dev_id < 0) {
dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
if (dev_id < 0) {
fprintf(stderr, "Not connected.\n");
exit(1);
}
}
dd = hci_open_dev(dev_id);
if (dd < 0) {
perror("HCI device open failed");
exit(1);
}
cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
if (!cr) {
perror("Can't allocate memory");
exit(1);
}
bacpy(&cr->bdaddr, &bdaddr);
cr->type = ACL_LINK;
if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
perror("Get connection info failed");
exit(1);
}
encrypt = (argc > 1) ? atoi(argv[1]) : 1;
if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), encrypt, 25000) < 0) {
perror("HCI set encryption request failed");
exit(1);
}
free(cr);
hci_close_dev(dd);
}
Solution 2:[2]
You can download the newest version of the source code here: http://www.bluez.org/ There ist the tool "btmgmt" and also the bluez-simple-agent that can be used for pairing. The code is all in the sources and there is also some documentation (in docs folder). Maybe you can use code of one of these tools for your desires or maybe it helps you understand the pairing.
I want to pair 2 device with the bluez bluetooth library in the first place but I happend to find helpful code in the source for the bluez-tools. There is the file "btmgmt.c" and some files that are include in it which implement the pairing.
For me unfortunately it is not working and I can't understand why. But maybe you have more success with it. Here is how you can test it.
If you haven't already, download the newest version of the source code here: http://www.bluez.org/ Extract it and open a terminal in the bluez folder.
Then run the following in the terminal:
./configure --prefix=/usr \
--sysconfdir=/etc \
--localstatedir=/var \
--enable-tools \
--disable-test \
--disable-systemd
I don't remember all packages you need to install but you can run this command and check why it fails, then install the package and rerun it till it works. Ask google if you don't know which package you need to install. Afterwards:
make
Now you can switch into tools folder from terminal and type ./btmgmt to see how to use it. You can also intall it to be able to use it by just typing "btmgmt" regardless of your location.
sudo /usr/bin/install -c tools/btmgmt /usr/bin/btmgmt
You need sudo rights to use it.
Solution 3:[3]
This dbus command can be used to initiate pairing
dbus-send --system --print-reply --dest=org.bluez /org/bluez/1301/hci0 org.bluez.Adapter.CreatePairedDevice string:"XX:XX:XX:XX:XX:XX" objpath:/org/bluez/agent_1317 string:"NoInputNoOutput"
Here 1301 is the process id of bluetoothd
/org/bluez/agent_1317 is the bluetooth pairing agent.The bluezagent that comes as agent.c in bluez/test can be used for this purpose.
Solution 4:[4]
I used to play around with Bluez in C/C++. As far as I can understand, C/C++ interface is not really welcome in BlueZ for users, it do prefers python.
So the main idea is to take a look at BlueZ repo, at directory /tools which implements some of required features in C.
Also, you can take a look at this article which shows some possibilities of BlueZ usage from plain C: https://people.csail.mit.edu/albert/bluez-intro/c404.html
Here is what i came up with (based on hcidump): https://github.com/IGR2014/Alsa-BlueZ-Example (inspired by https://github.com/pauloborges/bluez, https://git.kernel.org/pub/scm/bluetooth/bluez.git)
Small example of possible implementation for connect function:
// Connect to device
bool btCore::connect(const char* address) {
std::cout << "Connecting to device\t" << address << " ..." << std::endl;
std::cout << std::endl;
uint16_t handle;
unsigned int ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5;
char addr[19] = {0};
bdaddr_t bdaddr;
str2ba(address, &bdaddr);
// Open local HCI device
int sk = hci_open_dev(dev_id);
if (sk < 0) {
std::cerr << "HCI open device:\t\t" << strerror(errno) << std::endl;
return false;
}
// Establish HCI connection with device
if (hci_create_connection(sk, &bdaddr, htobs(ptype), 0, 0, &handle, 0) < 0) {
std::cerr << "HCI create connection:\t" << strerror(errno) << std::endl;
close(sk);
return false;
} else {
std::cout << "Connection:\t\tOK" << std::endl;
}
// Authenticate HCI link (without pin)
if (hci_authenticate_link(sk, handle, 0) < 0) {
std::cerr << "HCI authenticate connection:\t" << strerror(errno) << std::endl;
close(sk);
return false;
} else {
std::cout << "Authentication:\t\tOK" << std::endl;
}
// Encrypt HCI link
if (hci_encrypt_link(sk, handle, 1, 0) < 0) {
std::cerr << "HCI encrypt connection:\t" << strerror(errno) << std::endl;
close(sk);
return false;
} else {
std::cout << "Encryption:\t\tOK" << std::endl;
}
close(sk);
return true;
}
Next thing you have to do is discover services (https://www.bluetooth.com/specifications/assigned-numbers/service-discovery)
Also here is my old question which can lead you to answer: C++ Bluetooth headphones under Linux over BlueZ
Please note: All of the API (if we can name those internal functions "API") is not guaranteed to be same for other versions of BlueZ. At least, there is no any warranty of such behavior.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | disable13 |
Solution 2 | |
Solution 3 | Sreedevi Srinivasan |
Solution 4 |