Linux Bluetooth Pairing Device Using BlueZ5.X C Way


The traditional way to connect a device using bluetoothctl tool provided by BlueZ is as follows:

Run the bluetoothctl tool from command line

$ bluetoothctl
[NEW] Controller 00:19:0E:0C:BE:40 tango-charlie [default]

Turn ON Pairing agent:

[bluetooth]# agent on
Agent registered

Start Scanning:

[bluetooth]# scan on
Discovery started
[CHG] Controller 00:19:0E:0C:BE:40 Discovering: yes
[NEW] Device 00:23:3A:AF:B1:20 00-23-3A-AF-B1-20
[CHG] Device D4:CA:6E:71:F2:A9 RSSI: -57
[NEW] Device A0:10:81:EE:D7:59 Galaxy S8
[CHG] Device A0:10:81:EE:D7:59 RSSI: -57

Stop Scanning:

[bluetooth]# scan off
[CHG] Device A0:10:81:EE:D7:59 RSSI is nil
[CHG] Device 5C:51:4F:E0:EF:4C RSSI is nil
[CHG] Controller 00:19:0E:0C:BE:40 Discovering: no
Discovery stopped

Pair To Bluetooth Device:

[bluetooth]# pair A0:10:81:EE:D7:59
Attempting to pair with A0:10:81:EE:D7:59
[CHG] Device A0:10:81:EE:D7:59 Connected: yes
Request confirmation
[agent] Confirm passkey 110310 (yes/no): yes
[CHG] Device A0:10:81:EE:D7:59 Modalias: bluetooth:v0075p0100d0200
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 00001105-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 0000110a-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 00001112-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 00001115-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 00001116-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 0000111f-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 0000112d-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 0000112f-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 00001132-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 00001200-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 00001800-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 00001801-0000-1000-8000-00805f9b34fb
[CHG] Device A0:10:81:EE:D7:59 UUIDs: 936da01f-9abd-4d9d-80c7-02af85c822a8
[CHG] Device A0:10:81:EE:D7:59 Paired: yes
Pairing successful
[CHG] Device A0:10:81:EE:D7:59 Connected: no


In the above example 00:19:0E:0C:BE:40 is my bluetooth mac-address, I am trying to pair to my phone using the tool bluetoothctl,
firstly I turn scan on (command 'scan on') so that I can discovery my S8, once its discovered, I turn off scanning (command 'scan off')
and then pair to my S8 (command 'pair A0:10:81:EE:D7:59').

After all the above steps, bluez5 creates a folder named 'A0:10:81:EE:D7:59' in your /var/lib/bluetooth/00:19:0E:0C:BE:40/ directory
where 00:19:0E:0C:BE:40 is your bluetooth mac-address. The newly created folder will have a file info, which will have the devices info.

For example as below:
root@tango-charlie:/var/lib/bluetooth/00:19:0E:0C:BE:40/A0:10:81:EE:D7:59# cat info
[General]
Name=Galaxy S8
Class=0x5a020c
SupportedTechnologies=BR/EDR;
Trusted=false
Blocked=false
Services=00001105-0000-1000-8000-00805f9b34fb;0000110a-0000-1000-8000-00805f9b34fb;0000110c-0000-1000-8000-00805f9b34fb;0000110e-0000-1000-8000-00805f9b34fb;00001112-0000-1000-8000-00805f9b34fb;00001115-0000-1000-8000-00805f9b34fb;00001116-0000-1000-8000-00805f9b34fb;0000111f-0000-1000-8000-00805f9b34fb;0000112d-0000-1000-8000-00805f9b34fb;0000112f-0000-1000-8000-00805f9b34fb;00001132-0000-1000-8000-00805f9b34fb;00001200-0000-1000-8000-00805f9b34fb;00001800-0000-1000-8000-00805f9b34fb;00001801-0000-1000-8000-00805f9b34fb;936da01f-9abd-4d9d-80c7-02af85c822a8;

[LinkKey]
Key=1191251A41D151FA911224141F12414A
Type=5
PINLength=0

[DeviceID]
Source=1
Vendor=117
Product=256
Version=512

Once the device is paired you can connect to the device as follows

[bluetooth]# connect A0:10:81:EE:D7:59
Attempting to connect to A0:10:81:EE:D7:59
Connection successful
[Galaxy S8]#

All the above works fine you are using it from the command line, If you want to use it from the C code it becomes tedious!, So I came with the tricky idea
to pair to a device without bluetoothctl.

To pair to a device you need to scan the device, you can find the C code at [1] where you get the mac address of the scanned device, Once you obtain the
mac address, pass it to below function and this will pair the device for you.

For a quick test you can do is:

$ hcitool scan
$ hcitool cc A0:10:81:EE:D7:59 && dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_A0_10_81_EE_D7_59 org.bluez.Device1.Pair

Note: The above connect + pair (hcitool cc xx:xx:xx && dbus-send ..) might not connect to first to go so you need to do it twice or thrice, that is the reason the below C code as well tries to do the same

Note: Where A0:10:81:EE:D7:59 is the mac address of the device which you want to pair.

The above commands should pair the device and should create the info file with the LinkKey section.

Following is the C implementation of the above:

int bluez_pair_device(char* addr, char *controller_baddr)
{
    char btaddr_str[19] = { '\0' };
    int retry_count = 0;
    char pair_cmd[512];
    char response[512];
    char keycmd[512];
    char hciinfo[50];
    FILE *fp;
    int ret;

    strcpy(btaddr_str, addr);

    /* pairing might already exists so check first */
    /* /var/lib/bluetooth/78:A5:04:23:4A:51/00:04:3E:9F:C1:3F/info */
    sprintf(keycmd, "cat /var/lib/bluetooth/%s/%s/info | grep Key=", controller_baddr, btaddr_str);
    fp = popen(keycmd, "r");
    if (fp) {
        if (fgets(response, sizeof(response) - 1, fp) != NULL) {
            pclose(fp);
            goto exit_pair;
        }
        printf("Pairing does not exists for: '%s'", btaddr_str);
        pclose(fp);
    }

    strcpy(response, btaddr_str);
    btaddr_str[2] = '_';
    btaddr_str[5] = '_';
    btaddr_str[8] = '_';
    btaddr_str[11] = '_';
    btaddr_str[14] = '_';
    sprintf(pair_cmd, "hcitool cc %s && dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_%s org.bluez.Device1.Pair",
        response,
        btaddr_str);

    sprintf(hciinfo, "hcitool info %s", response);
retry_pair:
    if (retry_count > 5)
        return -EINVAL;

    ret = system(pair_cmd);
    if (ret) {
        retry_count++;
        printf("%s failed to pair bl device: %s", __FUNCTION__, btaddr_str);
        printf("cmd: '%s'", pair_cmd);
        system(hciinfo);
    }

    fp = popen(keycmd, "r");
    if (!fp) {
        printf("%s failed to run cmd: '%s'", __FUNCTION__, keycmd);
        retry_count++;
        goto retry_pair;
    }
    if (fgets(response, sizeof(response) - 1, fp) == NULL) {
        pclose(fp);
        printf("%s LinkKey missing in file", __FUNCTION__);
        printf("cmd: '%s'", pair_cmd);
        retry_count++;
        goto retry_pair;
    }
    pclose(fp);

exit_pair:
    return 0;
}

[1] https://people.csail.mit.edu/albert/bluez-intro/c404.html

Comments

Post a Comment

Popular posts from this blog

Checkpatch From Linux

Linux mmap Based File Write